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 email to 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 
194  SCIP_Bool fillbranchcands; /**< should branching candidates be added to storage? */
195 
196  SCIP_Bool dualpresolve; /**< should dual presolving be applied? */
197  SCIP_Bool coeftightening; /**< should coeffisient tightening be applied? */
198  SCIP_Bool normalize; /**< should demands and capacity be normalized? */
199  SCIP_Bool disjunctive; /**< extract disjunctive constraints? */
200  SCIP_Bool detectdisjunctive; /**< search for conflict set via maximal cliques to detect disjunctive constraints */
201  SCIP_Bool detectvarbounds; /**< search for conflict set via maximal cliques to detect variable bound constraints */
202  SCIP_Bool usebdwidening; /**< should bound widening be used during conflict analysis? */
203  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
204  SCIP_Bool detectedredundant; /**< was detection of redundant constraints already performed? */
205 
206  SCIP_Longint maxnodes; /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
207 
208  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)); /**< method to use a single cumulative condition */
209 
210  /* statistic values which are collected if SCIP_STATISTIC is defined */
211 #ifdef SCIP_STATISTIC
212  SCIP_Longint nlbtimetable; /**< number of times the lower bound was tightened by the time-table propagator */
213  SCIP_Longint nubtimetable; /**< number of times the upper bound was tightened by the time-table propagator */
214  SCIP_Longint ncutofftimetable; /**< number of times the a cutoff was detected due to time-table propagator */
215  SCIP_Longint nlbedgefinder; /**< number of times the lower bound was tightened by the edge-finder propagator */
216  SCIP_Longint nubedgefinder; /**< number of times the upper bound was tightened by the edge-finder propagator */
217  SCIP_Longint ncutoffedgefinder; /**< number of times the a cutoff was detected due to edge-finder propagator */
218  SCIP_Longint ncutoffoverload; /**< number of times the a cutoff was detected due to overload checking via edge-finding */
219  SCIP_Longint nlbTTEF; /**< number of times the lower bound was tightened by time-table edge-finding */
220  SCIP_Longint nubTTEF; /**< number of times the upper bound was tightened by time-table edge-finding */
221  SCIP_Longint ncutoffoverloadTTEF;/**< number of times the a cutoff was detected due to overload checking via time-table edge-finding */
222 
223  int nirrelevantjobs; /**< number of time a irrelevant/redundant jobs was removed form a constraint */
224  int nalwaysruns; /**< number of time a job removed form a constraint which run completely during the effective horizon */
225  int nremovedlocks; /**< number of times a up or down lock was removed */
226  int ndualfixs; /**< number of times a dual fix was performed by a single constraint */
227  int ndecomps; /**< number of times a constraint was decomposed */
228  int ndualbranchs; /**< number of times a dual branch was discoverd and applicable via probing */
229  int nallconsdualfixs; /**< number of times a dual fix was performed due to knowledge of all cumulative constraints */
230  int naddedvarbounds; /**< number of added variable bounds constraints */
231  int naddeddisjunctives; /**< number of added disjunctive constraints */
232 
233  SCIP_Bool iscopy; /**< Boolean to store if constraint handler is part of a copy */
234 #endif
235 };
236 
237 /**@name Inference Information Methods
238  *
239  * An inference information can be passed with each domain reduction to SCIP. This information is passed back to the
240  * constraint handler if the corresponding bound change has to be explained. It can be used to store information which
241  * help to construct a reason/explanation for a bound change. The inference information is limited to size of integer.
242  *
243  * In case of the cumulative constraint handler we store the used propagation algorithms for that particular bound
244  * change and the earliest start and latest completion time of all jobs in the conflict set.
245  *
246  * @{
247  */
248 
249 /** Propagation rules */
250 enum Proprule
251 {
252  PROPRULE_1_CORETIMES = 1, /**< core-time propagator */
253  PROPRULE_2_EDGEFINDING = 2, /**< edge-finder */
254  PROPRULE_3_TTEF = 3 /**< time-table edeg-finding */
255 };
256 typedef enum Proprule PROPRULE;
258 /** inference information */
259 struct InferInfo
260 {
261  union
262  {
263  /** struct to use the inference information */
264  struct
265  {
266  unsigned int proprule:2; /**< propagation rule that was applied */
267  unsigned int data1:15; /**< data field one */
268  unsigned int data2:15; /**< data field two */
269  } asbits;
270  int asint; /**< inference information as a single int value */
271  } val;
272 };
273 typedef struct InferInfo INFERINFO;
275 /** converts an integer into an inference information */
276 static
277 INFERINFO intToInferInfo(
278  int i /**< integer to convert */
279  )
280 {
281  INFERINFO inferinfo;
282 
283  inferinfo.val.asint = i;
284 
285  return inferinfo;
286 }
287 
288 /** converts an inference information into an int */
289 static
290 int inferInfoToInt(
291  INFERINFO inferinfo /**< inference information to convert */
292  )
293 {
294  return inferinfo.val.asint;
295 }
296 
297 /** returns the propagation rule stored in the inference information */
298 static
300  INFERINFO inferinfo /**< inference information to convert */
301  )
302 {
303  return (PROPRULE) inferinfo.val.asbits.proprule;
304 }
305 
306 /** returns data field one of the inference information */
307 static
309  INFERINFO inferinfo /**< inference information to convert */
310  )
311 {
312  return (int) inferinfo.val.asbits.data1;
313 }
314 
315 /** returns data field two of the inference information */
316 static
318  INFERINFO inferinfo /**< inference information to convert */
319  )
320 {
321  return (int) inferinfo.val.asbits.data2;
322 }
323 
324 
325 /** constructs an inference information out of a propagation rule, an earliest start and a latest completion time */
326 static
327 INFERINFO getInferInfo(
328  PROPRULE proprule, /**< propagation rule that deduced the value */
329  int data1, /**< data field one */
330  int data2 /**< data field two */
331  )
332 {
333  INFERINFO inferinfo;
334 
335  /* check that the data menber are in the range of the available bits */
336  assert((int)proprule <= (1<<2)-1); /*lint !e685*/
337  assert(data1 >= 0 && data1 < (1<<15));
338  assert(data2 >= 0 && data2 < (1<<15));
339 
340  inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
341  inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
342  inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
343 
344  return inferinfo;
345 }
346 
347 /**@} */
348 
349 /*
350  * Local methods
351  */
352 
353 /**@name Miscellaneous Methods
354  *
355  * @{
356  */
357 
358 #ifndef NDEBUG
359 
360 /** compute the core of a job which lies in certain interval [begin, end) */
361 static
363  int begin, /**< begin of the interval */
364  int end, /**< end of the interval */
365  int ect, /**< earliest completion time */
366  int lst /**< latest start time */
367  )
368 {
369  int core;
370 
371  core = MAX(0, MIN(end, ect) - MAX(lst, begin));
372 
373  return core;
374 }
375 #else
376 #define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
377 #endif
378 
379 /** returns the implied earliest start time */
380 static
382  SCIP* scip, /**< SCIP data structure */
383  SCIP_VAR* var, /**< variable for which the implied est should be returned */
384  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
385  int* est /**< pointer to store the implied earliest start time */
386  )
387 { /*lint --e{715}*/
388 #if 0
389  SCIP_VAR** vbdvars;
390  SCIP_VAR* vbdvar;
391  SCIP_Real* vbdcoefs;
392  SCIP_Real* vbdconsts;
393  void* image;
394  int nvbdvars;
395  int v;
396 #endif
397 
398  (*est) = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
399 
400 #if 0
401  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
402 
403  nvbdvars = SCIPvarGetNVlbs(var);
404  vbdvars = SCIPvarGetVlbVars(var);
405  vbdcoefs = SCIPvarGetVlbCoefs(var);
406  vbdconsts = SCIPvarGetVlbConstants(var);
407 
408  for( v = 0; v < nvbdvars; ++v )
409  {
410  vbdvar = vbdvars[v];
411  assert(vbdvar != NULL);
412 
413  image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
414 
415  if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
416  {
417  int duration;
418  int vbdconst;
419 
420  duration = (int)(size_t)image;
421  vbdconst = SCIPconvertRealToInt(scip, vbdconsts[v]);
422 
423  SCIPdebugMsg(scip, "check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
425  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
426 
427  if( duration >= vbdconst )
428  {
429  int impliedest;
430 
431  impliedest = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
432 
433  if( (*est) < impliedest )
434  {
435  (*est) = impliedest;
436 
437  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
438  }
439  }
440  }
441  }
442 #endif
443 
444  return SCIP_OKAY;
445 }
446 
447 /** returns the implied latest completion time */
448 static
450  SCIP* scip, /**< SCIP data structure */
451  SCIP_VAR* var, /**< variable for which the implied est should be returned */
452  int duration, /**< duration of the given job */
453  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
454  int* lct /**< pointer to store the implied latest completion time */
455  )
456 { /*lint --e{715}*/
457 #if 0
458  SCIP_VAR** vbdvars;
459  SCIP_VAR* vbdvar;
460  SCIP_Real* vbdcoefs;
461  SCIP_Real* vbdconsts;
462  int nvbdvars;
463  int v;
464 #endif
465 
466  (*lct) = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
467 
468 #if 0
469  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
470 
471  nvbdvars = SCIPvarGetNVubs(var);
472  vbdvars = SCIPvarGetVubVars(var);
473  vbdcoefs = SCIPvarGetVubCoefs(var);
474  vbdconsts = SCIPvarGetVubConstants(var);
475 
476  for( v = 0; v < nvbdvars; ++v )
477  {
478  vbdvar = vbdvars[v];
479  assert(vbdvar != NULL);
480 
481  if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
482  {
483  int vbdconst;
484 
485  vbdconst = SCIPconvertRealToInt(scip, -vbdconsts[v]);
486 
487  SCIPdebugMsg(scip, "check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
489  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
490 
491  if( duration >= -vbdconst )
492  {
493  int impliedlct;
494 
495  impliedlct = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
496 
497  if( (*lct) > impliedlct )
498  {
499  (*lct) = impliedlct;
500 
501  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
502  }
503  }
504  }
505  }
506 #endif
507 
508  return SCIP_OKAY;
509 }
510 
511 /** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
512 static
514  SCIP* scip, /**< SCIP data structure */
515  SCIP_CONSDATA* consdata, /**< constraint data */
516  SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
517  int** coefs, /**< pointer to store the coefficients */
518  int* nvars, /**< number if collect binary variables */
519  int* startindices, /**< permutation with rspect to the start times */
520  int curtime, /**< current point in time */
521  int nstarted, /**< number of jobs that start before the curtime or at curtime */
522  int nfinished /**< number of jobs that finished before curtime or at curtime */
523  )
524 {
525  int nrowvars;
526  int startindex;
527  int size;
528 
529  size = 10;
530  nrowvars = 0;
531  startindex = nstarted - 1;
532 
533  SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
534  SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
535 
536  /* search for the (nstarted - nfinished) jobs which are active at curtime */
537  while( nstarted - nfinished > nrowvars )
538  {
539  SCIP_VAR* var;
540  int endtime;
541  int duration;
542  int demand;
543  int varidx;
544 
545  /* collect job information */
546  varidx = startindices[startindex];
547  assert(varidx >= 0 && varidx < consdata->nvars);
548 
549  var = consdata->vars[varidx];
550  duration = consdata->durations[varidx];
551  demand = consdata->demands[varidx];
552  assert(var != NULL);
553 
554  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
555 
556  /* check the end time of this job is larger than the curtime; in this case the job is still running */
557  if( endtime > curtime )
558  {
559  SCIP_VAR** binvars;
560  int* vals;
561  int nbinvars;
562  int start;
563  int end;
564  int b;
565 
566  /* check if the linking constraints exists */
567  assert(SCIPexistsConsLinking(scip, var));
568  assert(SCIPgetConsLinking(scip, var) != NULL);
569  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
570 
571  /* collect linking constraint information */
572  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
573  vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
574 
575  start = curtime - duration + 1;
576  end = MIN(curtime, endtime - duration);
577 
578  for( b = 0; b < nbinvars; ++b )
579  {
580  if( vals[b] < start )
581  continue;
582 
583  if( vals[b] > end )
584  break;
585 
586  assert(binvars[b] != NULL);
587 
588  /* ensure array proper array size */
589  if( size == *nvars )
590  {
591  size *= 2;
592  SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
593  SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
594  }
595 
596  (*vars)[*nvars] = binvars[b];
597  (*coefs)[*nvars] = demand;
598  (*nvars)++;
599  }
600  nrowvars++;
601  }
602 
603  startindex--;
604  }
605 
606  return SCIP_OKAY;
607 }
608 
609 /** collect all integer variable which belong to jobs which can run at the point of interest */
610 static
612  SCIP* scip, /**< SCIP data structure */
613  SCIP_CONSDATA* consdata, /**< constraint data */
614  SCIP_VAR*** activevars, /**< jobs that are currently running */
615  int* startindices, /**< permutation with rspect to the start times */
616  int curtime, /**< current point in time */
617  int nstarted, /**< number of jobs that start before the curtime or at curtime */
618  int nfinished, /**< number of jobs that finished before curtime or at curtime */
619  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
620  int* lhs /**< lhs for the new row sum of lbs + minoffset */
621  )
622 {
623  SCIP_VAR* var;
624  int startindex;
625  int endtime;
626  int duration;
627  int starttime;
628 
629  int varidx;
630  int sumofstarts;
631  int mindelta;
632  int counter;
633 
634  assert(curtime >= consdata->hmin);
635  assert(curtime < consdata->hmax);
636 
637  counter = 0;
638  sumofstarts = 0;
639 
640  mindelta = INT_MAX;
641 
642  startindex = nstarted - 1;
643 
644  /* search for the (nstarted - nfinished) jobs which are active at curtime */
645  while( nstarted - nfinished > counter )
646  {
647  assert(startindex >= 0);
648 
649  /* collect job information */
650  varidx = startindices[startindex];
651  assert(varidx >= 0 && varidx < consdata->nvars);
652 
653  var = consdata->vars[varidx];
654  duration = consdata->durations[varidx];
655  assert(duration > 0);
656  assert(var != NULL);
657 
658  if( lower )
659  starttime = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
660  else
661  starttime = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
662 
663  endtime = MIN(starttime + duration, consdata->hmax);
664 
665  /* check the end time of this job is larger than the curtime; in this case the job is still running */
666  if( endtime > curtime )
667  {
668  (*activevars)[counter] = var;
669  sumofstarts += starttime;
670  mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
671  counter++;
672  }
673 
674  startindex--;
675  }
676 
677  assert(mindelta > 0);
678  *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
679 
680  return SCIP_OKAY;
681 }
682 
683 /** initialize the sorted event point arrays */
684 static
686  SCIP* scip, /**< SCIP data structure */
687  int nvars, /**< number of start time variables (activities) */
688  SCIP_VAR** vars, /**< array of start time variables */
689  int* durations, /**< array of durations per start time variable */
690  int* starttimes, /**< array to store sorted start events */
691  int* endtimes, /**< array to store sorted end events */
692  int* startindices, /**< permutation with rspect to the start times */
693  int* endindices, /**< permutation with rspect to the end times */
694  SCIP_Bool local /**< shall local bounds be used */
695  )
696 {
697  SCIP_VAR* var;
698  int j;
699 
700  assert(vars != NULL || nvars == 0);
701 
702  /* assign variables, start and endpoints to arrays */
703  for ( j = 0; j < nvars; ++j )
704  {
705  assert(vars != NULL);
706 
707  var = vars[j];
708  assert(var != NULL);
709 
710  if( local )
711  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
712  else
713  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
714 
715  startindices[j] = j;
716 
717  if( local )
718  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
719  else
720  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
721 
722  endindices[j] = j;
723 
724  }
725 
726  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
727  SCIPsortIntInt(starttimes, startindices, j);
728  SCIPsortIntInt(endtimes, endindices, j);
729 }
730 
731 /** initialize the sorted event point arrays w.r.t. the given primal solutions */
732 static
734  SCIP* scip, /**< SCIP data structure */
735  SCIP_SOL* sol, /**< solution */
736  int nvars, /**< number of start time variables (activities) */
737  SCIP_VAR** vars, /**< array of start time variables */
738  int* durations, /**< array of durations per start time variable */
739  int* starttimes, /**< array to store sorted start events */
740  int* endtimes, /**< array to store sorted end events */
741  int* startindices, /**< permutation with rspect to the start times */
742  int* endindices /**< permutation with rspect to the end times */
743  )
744 {
745  SCIP_VAR* var;
746  int j;
747 
748  assert(vars != NULL || nvars == 0);
749 
750  /* assign variables, start and endpoints to arrays */
751  for ( j = 0; j < nvars; ++j )
752  {
753  assert(vars != NULL);
754 
755  var = vars[j];
756  assert(var != NULL);
757 
758  starttimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
759  startindices[j] = j;
760 
761  endtimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
762  endindices[j] = j;
763 
764  }
765 
766  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
767  SCIPsortIntInt(starttimes, startindices, j);
768  SCIPsortIntInt(endtimes, endindices, j);
769 }
770 
771 /** initialize the sorted event point arrays
772  *
773  * @todo Check the separation process!
774  */
775 static
777  SCIP* scip, /**< SCIP data structure */
778  SCIP_CONSDATA* consdata, /**< constraint data */
779  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
780  int* starttimes, /**< array to store sorted start events */
781  int* endtimes, /**< array to store sorted end events */
782  int* startindices, /**< permutation with rspect to the start times */
783  int* endindices, /**< permutation with rspect to the end times */
784  int* nvars, /**< number of variables that are integral */
785  SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
786  )
787 {
788  SCIP_VAR* var;
789  int tmpnvars;
790  int j;
791 
792  tmpnvars = consdata->nvars;
793  *nvars = 0;
794 
795  /* assign variables, start and endpoints to arrays */
796  for ( j = 0; j < tmpnvars; ++j )
797  {
798  var = consdata->vars[j];
799  assert(var != NULL);
800  assert(consdata->durations[j] > 0);
801  assert(consdata->demands[j] > 0);
802 
803  if( lower )
804  {
805  /* only consider jobs that are at their lower or upper bound */
806  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
807  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
808  continue;
809 
810 
811  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
812  startindices[*nvars] = j;
813 
814  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
815  endindices[*nvars] = j;
816 
817  SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
818  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
819  consdata->durations[j],
820  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
821  consdata->demands[startindices[*nvars]]);
822 
823  (*nvars)++;
824  }
825  else
826  {
827  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
828  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
829  continue;
830 
831  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
832  startindices[*nvars] = j;
833 
834  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
835  endindices[*nvars] = j;
836 
837  SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
838  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
839  consdata->durations[j],
840  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
841  consdata->demands[startindices[*nvars]]);
842 
843  (*nvars)++;
844  }
845  }
846 
847  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
848  SCIPsortIntInt(starttimes, startindices, *nvars);
849  SCIPsortIntInt(endtimes, endindices, *nvars);
850 
851 #ifdef SCIP_DEBUG
852  SCIPdebugMsg(scip, "sorted output %d\n", *nvars);
853 
854  for ( j = 0; j < *nvars; ++j )
855  {
856  SCIPdebugMsg(scip, "%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
857  startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
858  consdata->demands[startindices[j]]);
859  }
860 
861  for ( j = 0; j < *nvars; ++j )
862  {
863  SCIPdebugMsg(scip, "%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
864  consdata->demands[endindices[j]]);
865  }
866 #endif
867 }
868 
869 #ifdef SCIP_STATISTIC
870 /** this method checks for relevant intervals for energetic reasoning */
871 static
872 SCIP_RETCODE computeRelevantEnergyIntervals(
873  SCIP* scip, /**< SCIP data structure */
874  int nvars, /**< number of start time variables (activities) */
875  SCIP_VAR** vars, /**< array of start time variables */
876  int* durations, /**< array of durations */
877  int* demands, /**< array of demands */
878  int capacity, /**< cumulative capacity */
879  int hmin, /**< left bound of time axis to be considered (including hmin) */
880  int hmax, /**< right bound of time axis to be considered (not including hmax) */
881  int** timepoints, /**< array to store relevant points in time */
882  SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
883  int* ntimepoints, /**< pointer to store the number of timepoints */
884  int* maxdemand, /**< pointer to store maximum over all demands */
885  SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
886  )
887 {
888  int* starttimes; /* stores when each job is starting */
889  int* endtimes; /* stores when each job ends */
890  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
891  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
892 
893  SCIP_Real totaldemand;
894  int curtime; /* point in time which we are just checking */
895  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
896 
897  int j;
898 
899  assert( scip != NULL );
900  assert(durations != NULL);
901  assert(demands != NULL);
902  assert(capacity >= 0);
903 
904  /* if no activities are associated with this cumulative then this constraint is redundant */
905  if( nvars == 0 )
906  return SCIP_OKAY;
907 
908  assert(vars != NULL);
909 
910  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
911  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
912  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
913  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
914 
915  /* create event point arrays */
916  createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
917 
918  endindex = 0;
919  totaldemand = 0.0;
920 
921  *ntimepoints = 0;
922  (*timepoints)[0] = starttimes[0];
923  (*cumulativedemands)[0] = 0;
924  *maxdemand = 0;
925 
926  /* check each startpoint of a job whether the capacity is kept or not */
927  for( j = 0; j < nvars; ++j )
928  {
929  int lct;
930  int idx;
931 
932  curtime = starttimes[j];
933 
934  if( curtime >= hmax )
935  break;
936 
937  /* free all capacity usages of jobs the are no longer running */
938  while( endindex < nvars && endtimes[endindex] <= curtime )
939  {
940  int est;
941 
942  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
943  {
944  (*ntimepoints)++;
945  (*timepoints)[*ntimepoints] = endtimes[endindex];
946  (*cumulativedemands)[*ntimepoints] = 0;
947  }
948 
949  idx = endindices[endindex];
950  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
951  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
952  endindex++;
953 
954  (*cumulativedemands)[*ntimepoints] = totaldemand;
955  }
956 
957  idx = startindices[j];
958  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
959  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
960 
961  if( (*timepoints)[*ntimepoints] < curtime )
962  {
963  (*ntimepoints)++;
964  (*timepoints)[*ntimepoints] = curtime;
965  (*cumulativedemands)[*ntimepoints] = 0;
966  }
967 
968  (*cumulativedemands)[*ntimepoints] = totaldemand;
969 
970  /* add the relative capacity requirements for all job which start at the curtime */
971  while( j+1 < nvars && starttimes[j+1] == curtime )
972  {
973  ++j;
974  idx = startindices[j];
975  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
976  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
977 
978  (*cumulativedemands)[*ntimepoints] = totaldemand;
979  }
980  } /*lint --e{850}*/
981 
982  /* free all capacity usages of jobs that are no longer running */
983  while( endindex < nvars/* && endtimes[endindex] < hmax*/)
984  {
985  int est;
986  int idx;
987 
988  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
989  {
990  (*ntimepoints)++;
991  (*timepoints)[*ntimepoints] = endtimes[endindex];
992  (*cumulativedemands)[*ntimepoints] = 0;
993  }
994 
995  idx = endindices[endindex];
996  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
997  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
998  (*cumulativedemands)[*ntimepoints] = totaldemand;
999 
1000  ++endindex;
1001  }
1002 
1003  (*ntimepoints)++;
1004  /* compute minimum free capacity */
1005  (*minfreecapacity) = INT_MAX;
1006  for( j = 0; j < *ntimepoints; ++j )
1007  {
1008  if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
1009  *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
1010  }
1011 
1012  /* free buffer arrays */
1013  SCIPfreeBufferArray(scip, &endindices);
1014  SCIPfreeBufferArray(scip, &startindices);
1015  SCIPfreeBufferArray(scip, &endtimes);
1016  SCIPfreeBufferArray(scip, &starttimes);
1017 
1018  return SCIP_OKAY;
1019 }
1020 
1021 /** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1022 static
1023 SCIP_RETCODE evaluateCumulativeness(
1024  SCIP* scip, /**< pointer to scip */
1025  SCIP_CONS* cons /**< cumulative constraint */
1026  )
1027 {
1028  SCIP_CONSDATA* consdata;
1029  int nvars;
1030  int v;
1031  int capacity;
1032 
1033  /* output values: */
1034  SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
1035  SCIP_Real cumfactor1;
1036  SCIP_Real resstrength1; /* overall strength */
1037  SCIP_Real resstrength2; /* timepoint wise maximum */
1038 
1039  /* helpful variables: */
1040  SCIP_Real globalpeak;
1041  SCIP_Real globalmaxdemand;
1042 
1043  /* get constraint data structure */
1044  consdata = SCIPconsGetData(cons);
1045  assert(consdata != NULL);
1046 
1047  nvars = consdata->nvars;
1048  capacity = consdata->capacity;
1049  globalpeak = 0.0;
1050  globalmaxdemand = 0.0;
1051 
1052  disjfactor2 = 0.0;
1053  cumfactor1 = 0.0;
1054  resstrength2 = 0.0;
1055 
1056  /* check each starting time (==each job, but inefficient) */
1057  for( v = 0; v < nvars; ++v )
1058  {
1059  SCIP_Real peak;
1060  SCIP_Real maxdemand;
1061  SCIP_Real deltademand;
1062  int ndemands;
1063  int nlarge;
1064 
1065  int timepoint;
1066  int j;
1067  timepoint = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
1068  peak = consdata->demands[v];
1069  ndemands = 1;
1070  maxdemand = 0;
1071  nlarge = 0;
1072 
1073  if( consdata->demands[v] > capacity / 3 )
1074  nlarge++;
1075 
1076  for( j = 0; j < nvars; ++j )
1077  {
1078  int lb;
1079 
1080  if( j == v )
1081  continue;
1082 
1083  maxdemand = 0.0;
1084  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
1085 
1086  if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
1087  {
1088  peak += consdata->demands[j];
1089  ndemands++;
1090 
1091  if( consdata->demands[j] > consdata->capacity / 3 )
1092  nlarge++;
1093  }
1094  }
1095 
1096  deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
1097  globalpeak = MAX(globalpeak, peak);
1098  globalmaxdemand = MAX(globalmaxdemand, maxdemand);
1099 
1100  if( peak > capacity )
1101  {
1102  disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
1103  cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
1104  resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
1105  }
1106  }
1107 
1108  resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
1109 
1110  consdata->maxpeak = SCIPconvertRealToInt(scip, globalpeak);
1111  consdata->disjfactor2 = disjfactor2;
1112  consdata->cumfactor1 = cumfactor1;
1113  consdata->resstrength2 = resstrength2;
1114  consdata->resstrength1 = resstrength1;
1115 
1116  /* get estimated res strength */
1117  {
1118  int* timepoints;
1119  SCIP_Real* estimateddemands;
1120  int ntimepoints;
1121  int maxdemand;
1122  SCIP_Real minfreecapacity;
1123 
1124  SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
1125  SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
1126 
1127  ntimepoints = 0;
1128  minfreecapacity = INT_MAX;
1129 
1130 
1131  SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
1132  consdata->durations, consdata->demands,
1133  capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1134  &ntimepoints, &maxdemand, &minfreecapacity) );
1135 
1136  /* free buffer arrays */
1137  SCIPfreeBufferArray(scip, &estimateddemands);
1138  SCIPfreeBufferArray(scip, &timepoints);
1139 
1140  consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
1141  }
1142 
1143  SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
1144  SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
1145  consdata->estimatedstrength);
1146 
1147  return SCIP_OKAY;
1148 }
1149 #endif
1150 
1151 /** gets the active variables together with the constant */
1152 static
1154  SCIP* scip, /**< SCIP data structure */
1155  SCIP_VAR** var, /**< pointer to store the active variable */
1156  int* scalar, /**< pointer to store the scalar */
1157  int* constant /**< pointer to store the constant */
1158  )
1159 {
1160  if( !SCIPvarIsActive(*var) )
1161  {
1162  SCIP_Real realscalar;
1163  SCIP_Real realconstant;
1164 
1165  realscalar = 1.0;
1166  realconstant = 0.0;
1167 
1169 
1170  /* transform variable to active variable */
1171  SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
1172  assert(!SCIPisZero(scip, realscalar));
1173  assert(SCIPvarIsActive(*var));
1174 
1175  if( realconstant < 0.0 )
1176  (*constant) = -SCIPconvertRealToInt(scip, -realconstant);
1177  else
1178  (*constant) = SCIPconvertRealToInt(scip, realconstant);
1179 
1180  if( realscalar < 0.0 )
1181  (*scalar) = -SCIPconvertRealToInt(scip, -realscalar);
1182  else
1183  (*scalar) = SCIPconvertRealToInt(scip, realscalar);
1184  }
1185  else
1186  {
1187  (*scalar) = 1;
1188  (*constant) = 0;
1189  }
1190 
1191  assert(*scalar != 0);
1192 
1193  return SCIP_OKAY;
1194 }
1195 
1196 /** computes the total energy of all jobs */
1197 static
1198 int computeTotalEnergy(
1199  int* durations, /**< array of job durations */
1200  int* demands, /**< array of job demands */
1201  int njobs /**< number of jobs */
1202  )
1203 {
1204  int energy;
1205  int j;
1206 
1207  energy = 0;
1208 
1209  for( j = 0; j < njobs; ++j )
1210  energy += durations[j] * demands[j];
1211 
1212  return energy;
1213 }
1214 
1215 /**@} */
1216 
1217 /**@name Default method to solve a cumulative condition
1218  *
1219  * @{
1220  */
1221 
1222 /** setup and solve subscip to solve single cumulative condition */
1223 static
1225  SCIP* subscip, /**< subscip data structure */
1226  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
1227  int* durations, /**< array of durations */
1228  int* demands, /**< array of demands */
1229  int njobs, /**< number of jobs (activities) */
1230  int capacity, /**< cumulative capacity */
1231  int hmin, /**< left bound of time axis to be considered (including hmin) */
1232  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1233  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes (-1: no limit) */
1234  SCIP_Real timelimit, /**< time limit for solving in seconds */
1235  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
1236  SCIP_Real* ests, /**< array of earliest start times for each job */
1237  SCIP_Real* lsts, /**< array of latest start times for each job */
1238  SCIP_Bool* infeasible, /**< pointer to store if the subproblem was infeasible */
1239  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
1240  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
1241  SCIP_Bool* error /**< pointer to store if an error occurred */
1242  )
1243 {
1244  SCIP_VAR** subvars;
1245  SCIP_CONS* cons;
1246 
1247  char name[SCIP_MAXSTRLEN];
1248  int v;
1249  SCIP_RETCODE retcode;
1250 
1251  assert(subscip != NULL);
1252 
1253  /* copy all plugins */
1255 
1256  /* create the subproblem */
1257  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1258 
1259  SCIP_CALL( SCIPallocBlockMemoryArray(subscip, &subvars, njobs) );
1260 
1261  /* create for each job a start time variable */
1262  for( v = 0; v < njobs; ++v )
1263  {
1264  SCIP_Real objval;
1265 
1266  /* construct variable name */
1267  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
1268 
1269  if( objvals == NULL )
1270  objval = 0.0;
1271  else
1272  objval = objvals[v];
1273 
1274  SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
1275  SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
1276  }
1277 
1278  /* create cumulative constraint */
1279  SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
1280  njobs, subvars, durations, demands, capacity) );
1281 
1282  /* set effective horizon */
1283  SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
1284  SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
1285 
1286  /* add cumulative constraint */
1287  SCIP_CALL( SCIPaddCons(subscip, cons) );
1288  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1289 
1290  /* set CP solver settings
1291  *
1292  * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
1293  * time limit.
1294  */
1296 
1297  /* do not abort subproblem on CTRL-C */
1298  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1299 
1300  /* disable output to console */
1301  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1302 
1303  /* set limits for the subproblem */
1304  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1305  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1306  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1307 
1308  /* forbid recursive call of heuristics and separators solving subMIPs */
1309  SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
1310 
1311  /* solve single cumulative constraint by branch and bound */
1312  retcode = SCIPsolve(subscip);
1313 
1314  if( retcode != SCIP_OKAY )
1315  (*error) = TRUE;
1316  else
1317  {
1318  SCIPdebugMsg(subscip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1319 
1320  /* evaluated solution status */
1321  switch( SCIPgetStatus(subscip) )
1322  {
1323  case SCIP_STATUS_INFORUNBD:
1325  (*infeasible) = TRUE;
1326  (*solved) = TRUE;
1327  break;
1328  case SCIP_STATUS_UNBOUNDED:
1329  (*unbounded) = TRUE;
1330  (*solved) = TRUE;
1331  break;
1332  case SCIP_STATUS_OPTIMAL:
1333  {
1334  SCIP_SOL* sol;
1335  SCIP_Real solval;
1336 
1337  sol = SCIPgetBestSol(subscip);
1338  assert(sol != NULL);
1339 
1340  for( v = 0; v < njobs; ++v )
1341  {
1342  solval = SCIPgetSolVal(subscip, sol, subvars[v]);
1343 
1344  ests[v] = solval;
1345  lsts[v] = solval;
1346  }
1347  (*solved) = TRUE;
1348  break;
1349  }
1350  case SCIP_STATUS_NODELIMIT:
1352  case SCIP_STATUS_TIMELIMIT:
1353  case SCIP_STATUS_MEMLIMIT:
1355  /* transfer the global bound changes */
1356  for( v = 0; v < njobs; ++v )
1357  {
1358  ests[v] = SCIPvarGetLbGlobal(subvars[v]);
1359  lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
1360  }
1361  (*solved) = FALSE;
1362  break;
1363 
1364  case SCIP_STATUS_UNKNOWN:
1366  case SCIP_STATUS_GAPLIMIT:
1367  case SCIP_STATUS_SOLLIMIT:
1370  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1371  return SCIP_INVALIDDATA;
1372  }
1373  }
1374 
1375  /* release all variables */
1376  for( v = 0; v < njobs; ++v )
1377  {
1378  SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1379  }
1380 
1381  SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
1382 
1383  return SCIP_OKAY;
1384 }
1385 
1386 /** solve single cumulative condition using SCIP and a single cumulative constraint */
1387 static
1388 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1390  SCIP* subscip;
1391 
1392  SCIP_RETCODE retcode;
1393 
1394  assert(njobs > 0);
1395 
1396  (*solved) = FALSE;
1397  (*infeasible) = FALSE;
1398  (*unbounded) = FALSE;
1399  (*error) = FALSE;
1400 
1401  SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1402 
1403  /* initialize the sub-problem */
1404  SCIP_CALL( SCIPcreate(&subscip) );
1405 
1406  /* create and solve the subproblem. catch possible errors */
1407  retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
1408  njobs, capacity, hmin, hmax,
1409  maxnodes, timelimit, memorylimit,
1410  ests, lsts,
1411  infeasible, unbounded, solved, error);
1412 
1413  /* free the subscip in any case */
1414  SCIP_CALL( SCIPfree(&subscip) );
1415 
1416  SCIP_CALL( retcode );
1417 
1418  return SCIP_OKAY;
1419 }
1420 
1421 #if 0
1422 /** solve single cumulative condition using SCIP and the time indexed formulation */
1423 static
1424 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1425 {
1426  SCIP* subscip;
1427  SCIP_VAR*** binvars;
1428  SCIP_RETCODE retcode;
1429  char name[SCIP_MAXSTRLEN];
1430  int minest;
1431  int maxlct;
1432  int t;
1433  int v;
1434 
1435  assert(njobs > 0);
1436 
1437  (*solved) = FALSE;
1438  (*infeasible) = FALSE;
1439  (*unbounded) = FALSE;
1440  (*error) = FALSE;
1441 
1442  SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
1443 
1444  /* initialize the sub-problem */
1445  SCIP_CALL( SCIPcreate(&subscip) );
1446 
1447  /* copy all plugins */
1449 
1450  /* create the subproblem */
1451  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1452 
1453  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
1454 
1455  minest = INT_MAX;
1456  maxlct = INT_MIN;
1457 
1458  /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1459  * partitioning constrain which forces that job starts
1460  */
1461  for( v = 0; v < njobs; ++v )
1462  {
1463  SCIP_CONS* cons;
1464  SCIP_Real objval;
1465  int timeinterval;
1466  int est;
1467  int lst;
1468 
1469  if( objvals == NULL )
1470  objval = 0.0;
1471  else
1472  objval = objvals[v];
1473 
1474  est = ests[v];
1475  lst = lsts[v];
1476 
1477  /* compute number of possible start points */
1478  timeinterval = lst - est + 1;
1479  assert(timeinterval > 0);
1480 
1481  /* compute the smallest earliest start time and largest latest completion time */
1482  minest = MIN(minest, est);
1483  maxlct = MAX(maxlct, lst + durations[v]);
1484 
1485  /* construct constraint name */
1486  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1487 
1488  SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1489 
1490  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
1491 
1492  for( t = 0; t < timeinterval; ++t )
1493  {
1494  SCIP_VAR* binvar;
1495 
1496  /* construct varibale name */
1497  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1498 
1499  SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1500  SCIP_CALL( SCIPaddVar(subscip, binvar) );
1501 
1502  /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1503  SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1504 
1505  binvars[v][t] = binvar;
1506  }
1507 
1508  /* add and release the set partitioning constraint */
1509  SCIP_CALL( SCIPaddCons(subscip, cons) );
1510  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1511  }
1512 
1513  /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1514  hmin = MAX(hmin, minest);
1515  hmax = MIN(hmax, maxlct);
1516  assert(hmin > INT_MIN);
1517  assert(hmax < INT_MAX);
1518  assert(hmin < hmax);
1519 
1520  /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1521  for( t = hmin; t < hmax; ++t )
1522  {
1523  SCIP_CONS* cons;
1524 
1525  /* construct constraint name */
1526  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1527 
1528  /* create an empty knapsack constraint */
1529  SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1530 
1531  /* add all jobs which potentially can be processed at that time point */
1532  for( v = 0; v < njobs; ++v )
1533  {
1534  int duration;
1535  int demand;
1536  int start;
1537  int end;
1538  int est;
1539  int lst;
1540  int k;
1541 
1542  est = ests[v];
1543  lst = lsts[v] ;
1544 
1545  duration = durations[v];
1546  assert(duration > 0);
1547 
1548  /* check if the varibale is processed potentially at time point t */
1549  if( t < est || t >= lst + duration )
1550  continue;
1551 
1552  demand = demands[v];
1553  assert(demand >= 0);
1554 
1555  start = MAX(t - duration + 1, est);
1556  end = MIN(t, lst);
1557 
1558  assert(start <= end);
1559 
1560  for( k = start; k <= end; ++k )
1561  {
1562  assert(binvars[v][k] != NULL);
1563  SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1564  }
1565  }
1566 
1567  /* add and release the knapsack constraint */
1568  SCIP_CALL( SCIPaddCons(subscip, cons) );
1569  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1570  }
1571 
1572  /* do not abort subproblem on CTRL-C */
1573  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1574 
1575  /* disable output to console */
1576  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1577 
1578  /* set limits for the subproblem */
1579  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1580  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1581  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1582 
1583  /* solve single cumulative constraint by branch and bound */
1584  retcode = SCIPsolve(subscip);
1585 
1586  if( retcode != SCIP_OKAY )
1587  (*error) = TRUE;
1588  else
1589  {
1590  SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1591 
1592  /* evaluated solution status */
1593  switch( SCIPgetStatus(subscip) )
1594  {
1595  case SCIP_STATUS_INFORUNBD:
1597  (*infeasible) = TRUE;
1598  (*solved) = TRUE;
1599  break;
1600  case SCIP_STATUS_UNBOUNDED:
1601  (*unbounded) = TRUE;
1602  (*solved) = TRUE;
1603  break;
1604  case SCIP_STATUS_OPTIMAL:
1605  {
1606  SCIP_SOL* sol;
1607 
1608  sol = SCIPgetBestSol(subscip);
1609  assert(sol != NULL);
1610 
1611  for( v = 0; v < njobs; ++v )
1612  {
1613  int timeinterval;
1614  int est;
1615  int lst;
1616 
1617  est = ests[v];
1618  lst = lsts[v];
1619 
1620  /* compute number of possible start points */
1621  timeinterval = lst - est + 1;
1622 
1623  /* check which binary varibale is set to one */
1624  for( t = 0; t < timeinterval; ++t )
1625  {
1626  if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1627  {
1628  ests[v] = est + t;
1629  lsts[v] = est + t;
1630  break;
1631  }
1632  }
1633  }
1634 
1635  (*solved) = TRUE;
1636  break;
1637  }
1638  case SCIP_STATUS_NODELIMIT:
1640  case SCIP_STATUS_TIMELIMIT:
1641  case SCIP_STATUS_MEMLIMIT:
1643  /* transfer the global bound changes */
1644  for( v = 0; v < njobs; ++v )
1645  {
1646  int timeinterval;
1647  int est;
1648  int lst;
1649 
1650  est = ests[v];
1651  lst = lsts[v];
1652 
1653  /* compute number of possible start points */
1654  timeinterval = lst - est + 1;
1655 
1656  /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1657  for( t = 0; t < timeinterval; ++t )
1658  {
1659  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1660  {
1661  ests[v] = est + t;
1662  break;
1663  }
1664  }
1665 
1666  /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1667  for( t = timeinterval - 1; t >= 0; --t )
1668  {
1669  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1670  {
1671  lsts[v] = est + t;
1672  break;
1673  }
1674  }
1675  }
1676  (*solved) = FALSE;
1677  break;
1678 
1679  case SCIP_STATUS_UNKNOWN:
1681  case SCIP_STATUS_GAPLIMIT:
1682  case SCIP_STATUS_SOLLIMIT:
1684  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1685  return SCIP_INVALIDDATA;
1686  }
1687  }
1688 
1689  /* release all variables */
1690  for( v = 0; v < njobs; ++v )
1691  {
1692  int timeinterval;
1693  int est;
1694  int lst;
1695 
1696  est = ests[v];
1697  lst = lsts[v];
1698 
1699  /* compute number of possible start points */
1700  timeinterval = lst - est + 1;
1701 
1702  for( t = 0; t < timeinterval; ++t )
1703  {
1704  SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1705  }
1706  SCIPfreeBufferArray(subscip, &binvars[v]);
1707  }
1708 
1709  SCIPfreeBufferArray(subscip, &binvars);
1710 
1711  SCIP_CALL( SCIPfree(&subscip) );
1712 
1713  return SCIP_OKAY;
1714 }
1715 #endif
1716 
1717 /**@} */
1718 
1719 /**@name Constraint handler data
1720  *
1721  * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1722  * handler.
1723  *
1724  * @{
1725  */
1726 
1727 /** creates constaint handler data for cumulative constraint handler */
1728 static
1730  SCIP* scip, /**< SCIP data structure */
1731  SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1732  SCIP_EVENTHDLR* eventhdlr /**< event handler */
1733  )
1734 {
1735  /* create precedence constraint handler data */
1736  assert(scip != NULL);
1737  assert(conshdlrdata != NULL);
1738  assert(eventhdlr != NULL);
1739 
1740  SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
1741 
1742  /* set event handler for checking if bounds of start time variables are tighten */
1743  (*conshdlrdata)->eventhdlr = eventhdlr;
1744 
1745  /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1746  (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1747 
1748 #ifdef SCIP_STATISTIC
1749  (*conshdlrdata)->nlbtimetable = 0;
1750  (*conshdlrdata)->nubtimetable = 0;
1751  (*conshdlrdata)->ncutofftimetable = 0;
1752  (*conshdlrdata)->nlbedgefinder = 0;
1753  (*conshdlrdata)->nubedgefinder = 0;
1754  (*conshdlrdata)->ncutoffedgefinder = 0;
1755  (*conshdlrdata)->ncutoffoverload = 0;
1756  (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1757 
1758  (*conshdlrdata)->nirrelevantjobs = 0;
1759  (*conshdlrdata)->nalwaysruns = 0;
1760  (*conshdlrdata)->nremovedlocks = 0;
1761  (*conshdlrdata)->ndualfixs = 0;
1762  (*conshdlrdata)->ndecomps = 0;
1763  (*conshdlrdata)->ndualbranchs = 0;
1764  (*conshdlrdata)->nallconsdualfixs = 0;
1765  (*conshdlrdata)->naddedvarbounds = 0;
1766  (*conshdlrdata)->naddeddisjunctives = 0;
1767 #endif
1768 
1769  return SCIP_OKAY;
1770 }
1771 
1772 /** frees constraint handler data for logic or constraint handler */
1773 static
1774 void conshdlrdataFree(
1775  SCIP* scip, /**< SCIP data structure */
1776  SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1777  )
1778 {
1779  assert(conshdlrdata != NULL);
1780  assert(*conshdlrdata != NULL);
1781 
1782  SCIPfreeBlockMemory(scip, conshdlrdata);
1783 }
1784 
1785 /**@} */
1786 
1787 
1788 /**@name Constraint data methods
1789  *
1790  * @{
1791  */
1792 
1793 /** catches bound change events for all variables in transformed cumulative constraint */
1794 static
1796  SCIP* scip, /**< SCIP data structure */
1797  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1798  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1799  )
1800 {
1801  int v;
1802 
1803  assert(scip != NULL);
1804  assert(consdata != NULL);
1805  assert(eventhdlr != NULL);
1806 
1807  /* catch event for every single variable */
1808  for( v = 0; v < consdata->nvars; ++v )
1809  {
1810  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1811  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1812  }
1813 
1814  return SCIP_OKAY;
1815 }
1816 
1817 /** drops events for variable at given position */
1818 static
1820  SCIP* scip, /**< SCIP data structure */
1821  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1822  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1823  int pos /**< array position of variable to catch bound change events for */
1824  )
1825 {
1826  assert(scip != NULL);
1827  assert(consdata != NULL);
1828  assert(eventhdlr != NULL);
1829  assert(0 <= pos && pos < consdata->nvars);
1830  assert(consdata->vars[pos] != NULL);
1831 
1832  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1833  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1834 
1835  return SCIP_OKAY;
1836 }
1837 
1838 /** drops bound change events for all variables in transformed linear constraint */
1839 static
1841  SCIP* scip, /**< SCIP data structure */
1842  SCIP_CONSDATA* consdata, /**< linear constraint data */
1843  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1844  )
1845 {
1846  int v;
1847 
1848  assert(scip != NULL);
1849  assert(consdata != NULL);
1850 
1851  /* drop event of every single variable */
1852  for( v = 0; v < consdata->nvars; ++v )
1853  {
1854  SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1855  }
1856 
1857  return SCIP_OKAY;
1858 }
1859 
1860 /** initialize variable lock data structure */
1861 static
1862 void initializeLocks(
1863  SCIP_CONSDATA* consdata, /**< constraint data */
1864  SCIP_Bool locked /**< should the variable be locked? */
1865  )
1866 {
1867  int nvars;
1868  int v;
1869 
1870  nvars = consdata->nvars;
1871 
1872  /* initialize locking arrays */
1873  for( v = 0; v < nvars; ++v )
1874  {
1875  consdata->downlocks[v] = locked;
1876  consdata->uplocks[v] = locked;
1877  }
1878 }
1879 
1880 /** creates constraint data of cumulative constraint */
1881 static
1883  SCIP* scip, /**< SCIP data structure */
1884  SCIP_CONSDATA** consdata, /**< pointer to consdata */
1885  SCIP_VAR** vars, /**< array of integer variables */
1886  SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1887  int* durations, /**< array containing corresponding durations */
1888  int* demands, /**< array containing corresponding demands */
1889  int nvars, /**< number of variables */
1890  int capacity, /**< available cumulative capacity */
1891  int hmin, /**< left bound of time axis to be considered (including hmin) */
1892  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1893  SCIP_Bool check /**< is the corresponding constraint a check constraint */
1894  )
1895 {
1896  int v;
1897 
1898  assert(scip != NULL);
1899  assert(consdata != NULL);
1900  assert(vars != NULL || nvars > 0);
1901  assert(demands != NULL);
1902  assert(durations != NULL);
1903  assert(capacity >= 0);
1904  assert(hmin >= 0);
1905  assert(hmin < hmax);
1906 
1907  /* create constraint data */
1908  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1909 
1910  (*consdata)->hmin = hmin;
1911  (*consdata)->hmax = hmax;
1912 
1913  (*consdata)->capacity = capacity;
1914  (*consdata)->demandrows = NULL;
1915  (*consdata)->demandrowssize = 0;
1916  (*consdata)->ndemandrows = 0;
1917  (*consdata)->scoverrows = NULL;
1918  (*consdata)->nscoverrows = 0;
1919  (*consdata)->scoverrowssize = 0;
1920  (*consdata)->bcoverrows = NULL;
1921  (*consdata)->nbcoverrows = 0;
1922  (*consdata)->bcoverrowssize = 0;
1923  (*consdata)->nvars = nvars;
1924  (*consdata)->varssize = nvars;
1925  (*consdata)->signature = 0;
1926  (*consdata)->validsignature = FALSE;
1927  (*consdata)->normalized = FALSE;
1928  (*consdata)->covercuts = FALSE;
1929  (*consdata)->propagated = FALSE;
1930  (*consdata)->varbounds = FALSE;
1931  (*consdata)->triedsolving = FALSE;
1932 
1933  if( nvars > 0 )
1934  {
1935  assert(vars != NULL); /* for flexelint */
1936 
1937  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1938  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1939  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1940  (*consdata)->linkingconss = NULL;
1941 
1942  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1943  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1944 
1945  /* initialize variable lock data structure; the locks are only used if the contraint is a check constraint */
1946  initializeLocks(*consdata, check);
1947 
1948  if( linkingconss != NULL )
1949  {
1950  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
1951  }
1952 
1953  /* transform variables, if they are not yet transformed */
1954  if( SCIPisTransformed(scip) )
1955  {
1956  SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
1957 
1958  /* get transformed variables and do NOT captures these */
1959  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1960 
1961  /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
1962  * been multi-aggregated
1963  */
1964  for( v = 0; v < nvars; ++v )
1965  {
1966  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
1967  }
1968 
1969  if( linkingconss != NULL )
1970  {
1971  /* get transformed constraints and captures these */
1972  SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
1973 
1974  for( v = 0; v < nvars; ++v )
1975  assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
1976  }
1977  }
1978  }
1979  else
1980  {
1981  (*consdata)->vars = NULL;
1982  (*consdata)->downlocks = NULL;
1983  (*consdata)->uplocks = NULL;
1984  (*consdata)->demands = NULL;
1985  (*consdata)->durations = NULL;
1986  (*consdata)->linkingconss = NULL;
1987  }
1988 
1989  /* initialize values for running propagation algorithms efficiently */
1990  (*consdata)->resstrength1 = -1.0;
1991  (*consdata)->resstrength2 = -1.0;
1992  (*consdata)->cumfactor1 = -1.0;
1993  (*consdata)->disjfactor1 = -1.0;
1994  (*consdata)->disjfactor2 = -1.0;
1995  (*consdata)->estimatedstrength = -1.0;
1996 
1997  SCIPstatistic( (*consdata)->maxpeak = -1 );
1998 
1999  return SCIP_OKAY;
2000 }
2001 
2002 /** releases LP rows of constraint data and frees rows array */
2003 static
2005  SCIP* scip, /**< SCIP data structure */
2006  SCIP_CONSDATA** consdata /**< constraint data */
2007  )
2008 {
2009  int r;
2010 
2011  assert(consdata != NULL);
2012  assert(*consdata != NULL);
2013 
2014  for( r = 0; r < (*consdata)->ndemandrows; ++r )
2015  {
2016  assert((*consdata)->demandrows[r] != NULL);
2017  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
2018  }
2019 
2020  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
2021 
2022  (*consdata)->ndemandrows = 0;
2023  (*consdata)->demandrowssize = 0;
2024 
2025  /* free rows of cover cuts */
2026  for( r = 0; r < (*consdata)->nscoverrows; ++r )
2027  {
2028  assert((*consdata)->scoverrows[r] != NULL);
2029  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
2030  }
2031 
2032  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
2033 
2034  (*consdata)->nscoverrows = 0;
2035  (*consdata)->scoverrowssize = 0;
2036 
2037  for( r = 0; r < (*consdata)->nbcoverrows; ++r )
2038  {
2039  assert((*consdata)->bcoverrows[r] != NULL);
2040  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2041  }
2042 
2043  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2044 
2045  (*consdata)->nbcoverrows = 0;
2046  (*consdata)->bcoverrowssize = 0;
2047 
2048  (*consdata)->covercuts = FALSE;
2049 
2050  return SCIP_OKAY;
2051 }
2052 
2053 /** frees a cumulative constraint data */
2054 static
2056  SCIP* scip, /**< SCIP data structure */
2057  SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2058  )
2059 {
2060  int varssize;
2061  int nvars;
2062 
2063  assert(consdata != NULL);
2064  assert(*consdata != NULL);
2065 
2066  nvars = (*consdata)->nvars;
2067  varssize = (*consdata)->varssize;
2068 
2069  if( varssize > 0 )
2070  {
2071  int v;
2072 
2073  /* release and free the rows */
2074  SCIP_CALL( consdataFreeRows(scip, consdata) );
2075 
2076  /* release the linking constraints if they were generated */
2077  if( (*consdata)->linkingconss != NULL )
2078  {
2079  for( v = nvars-1; v >= 0; --v )
2080  {
2081  assert((*consdata)->linkingconss[v] != NULL );
2082  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2083  }
2084 
2085  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2086  }
2087 
2088  /* free arrays */
2089  SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2090  SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2091  SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2092  SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2093  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2094  }
2095 
2096  /* free memory */
2097  SCIPfreeBlockMemory(scip, consdata);
2098 
2099  return SCIP_OKAY;
2100 }
2101 
2102 /** prints cumulative constraint to file stream */
2103 static
2104 void consdataPrint(
2105  SCIP* scip, /**< SCIP data structure */
2106  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2107  FILE* file /**< output file (or NULL for standard output) */
2108  )
2109 {
2110  int v;
2111 
2112  assert(consdata != NULL);
2113 
2114  /* print coefficients */
2115  SCIPinfoMessage( scip, file, "cumulative(");
2116 
2117  for( v = 0; v < consdata->nvars; ++v )
2118  {
2119  assert(consdata->vars[v] != NULL);
2120  if( v > 0 )
2121  SCIPinfoMessage(scip, file, ", ");
2122  SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2123  SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2124  consdata->durations[v], consdata->demands[v]);
2125  }
2126  SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2127 }
2128 
2129 /** deletes coefficient at given position from constraint data */
2130 static
2132  SCIP* scip, /**< SCIP data structure */
2133  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2134  SCIP_CONS* cons, /**< knapsack constraint */
2135  int pos /**< position of coefficient to delete */
2136  )
2137 {
2138  SCIP_CONSHDLR* conshdlr;
2139  SCIP_CONSHDLRDATA* conshdlrdata;
2140 
2141  assert(scip != NULL);
2142  assert(consdata != NULL);
2143  assert(cons != NULL);
2144  assert(SCIPconsIsTransformed(cons));
2145  assert(!SCIPinProbing(scip));
2146 
2147  SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2148  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2149 
2150  /* remove the rounding locks for the deleted variable */
2151  SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2152 
2153  consdata->downlocks[pos] = FALSE;
2154  consdata->uplocks[pos] = FALSE;
2155 
2156  if( consdata->linkingconss != NULL )
2157  {
2158  SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2159  }
2160 
2161  /* get event handler */
2162  conshdlr = SCIPconsGetHdlr(cons);
2163  assert(conshdlr != NULL);
2164  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2165  assert(conshdlrdata != NULL);
2166  assert(conshdlrdata->eventhdlr != NULL);
2167 
2168  /* drop events */
2169  SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2170 
2171  SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2172  SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2173 
2174 
2175  /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2176  * position
2177  */
2178  if( pos != consdata->nvars - 1 )
2179  {
2180  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2181  consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2182  consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2183  consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2184  consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2185 
2186  if( consdata->linkingconss != NULL )
2187  {
2188  consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2189  }
2190  }
2191 
2192  consdata->nvars--;
2193  consdata->validsignature = FALSE;
2194  consdata->normalized = FALSE;
2195 
2196  return SCIP_OKAY;
2197 }
2198 
2199 /** collect linking constraints for each integer variable */
2200 static
2202  SCIP* scip, /**< SCIP data structure */
2203  SCIP_CONSDATA* consdata /**< pointer to consdata */
2204  )
2205 {
2206  int nvars;
2207  int v;
2208 
2209  assert(scip != NULL);
2210  assert(consdata != NULL);
2211 
2212  nvars = consdata->nvars;
2213  assert(nvars > 0);
2214  assert(consdata->linkingconss == NULL);
2215 
2216  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2217 
2218  for( v = 0; v < nvars; ++v )
2219  {
2220  SCIP_CONS* cons;
2221  SCIP_VAR* var;
2222 
2223  var = consdata->vars[v];
2224  assert(var != NULL);
2225 
2226  SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2227 
2228  /* create linking constraint if it does not exist yet */
2229  if( !SCIPexistsConsLinking(scip, var) )
2230  {
2231  char name[SCIP_MAXSTRLEN];
2232 
2233  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2234 
2235  /* creates and captures an linking constraint */
2236  SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2237  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2238  SCIP_CALL( SCIPaddCons(scip, cons) );
2239  consdata->linkingconss[v] = cons;
2240  }
2241  else
2242  {
2243  consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2244  SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2245  }
2246 
2247  assert(SCIPexistsConsLinking(scip, var));
2248  assert(consdata->linkingconss[v] != NULL);
2249  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2250  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2251  }
2252 
2253  return SCIP_OKAY;
2254 }
2255 
2256 /**@} */
2257 
2258 
2259 /**@name Check methods
2260  *
2261  * @{
2262  */
2263 
2264 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2265  * given solution is satisfied
2266  */
2267 static
2269  SCIP* scip, /**< SCIP data structure */
2270  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2271  int nvars, /**< number of variables (jobs) */
2272  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2273  int* durations, /**< array containing corresponding durations */
2274  int* demands, /**< array containing corresponding demands */
2275  int capacity, /**< available cumulative capacity */
2276  int hmin, /**< left bound of time axis to be considered (including hmin) */
2277  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2278  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2279  SCIP_CONS* cons, /**< constraint which is checked */
2280  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2281  )
2282 {
2283  int* startsolvalues; /* stores when each job is starting */
2284  int* endsolvalues; /* stores when each job ends */
2285  int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2286  int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2287 
2288  int freecapacity;
2289  int curtime; /* point in time which we are just checking */
2290  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2291  int j;
2292 
2293  SCIP_Real absviol;
2294  SCIP_Real relviol;
2295 
2296  assert(scip != NULL);
2297  assert(violated != NULL);
2298 
2299  (*violated) = FALSE;
2300 
2301  if( nvars == 0 )
2302  return SCIP_OKAY;
2303 
2304  assert(vars != NULL);
2305  assert(demands != NULL);
2306  assert(durations != NULL);
2307 
2308  /* compute time points where we have to check whether capacity constraint is infeasible or not */
2309  SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2310  SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2311  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2312  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2313 
2314  /* assign variables, start and endpoints to arrays */
2315  for ( j = 0; j < nvars; ++j )
2316  {
2317  int solvalue;
2318 
2319  /* the constraint of the cumulative constraint handler should be called after the integrality check */
2320  assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2321 
2322  solvalue = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2323 
2324  /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2325  * jobs which start before hmin to hmin
2326  */
2327  startsolvalues[j] = MAX(solvalue, hmin);
2328  startindices[j] = j;
2329 
2330  endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2331  endindices[j] = j;
2332  }
2333 
2334  /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2335  * corresponding indices in the same way)
2336  */
2337  SCIPsortIntInt(startsolvalues, startindices, nvars);
2338  SCIPsortIntInt(endsolvalues, endindices, nvars);
2339 
2340  endindex = 0;
2341  freecapacity = capacity;
2342  absviol = 0.0;
2343  relviol = 0.0;
2344 
2345  /* check each start point of a job whether the capacity is kept or not */
2346  for( j = 0; j < nvars; ++j )
2347  {
2348  /* only check intervals [hmin,hmax) */
2349  curtime = startsolvalues[j];
2350 
2351  if( curtime >= hmax )
2352  break;
2353 
2354  /* subtract all capacity needed up to this point */
2355  freecapacity -= demands[startindices[j]];
2356  while( j+1 < nvars && startsolvalues[j+1] == curtime )
2357  {
2358  j++;
2359  freecapacity -= demands[startindices[j]];
2360  }
2361 
2362  /* free all capacity usages of jobs that are no longer running */
2363  while( endindex < nvars && curtime >= endsolvalues[endindex] )
2364  {
2365  freecapacity += demands[endindices[endindex]];
2366  ++endindex;
2367  }
2368  assert(freecapacity <= capacity);
2369 
2370  /* update absolute and relative violation */
2371  if( absviol < (SCIP_Real) (-freecapacity) )
2372  {
2373  absviol = -freecapacity;
2374  relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
2375  }
2376 
2377  /* check freecapacity to be smaller than zero */
2378  if( freecapacity < 0 && curtime >= hmin )
2379  {
2380  SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2381  (*violated) = TRUE;
2382 
2383  if( printreason )
2384  {
2385  int i;
2386 
2387  /* first state the violated constraints */
2388  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2389 
2390  /* second state the reason */
2391  SCIPinfoMessage(scip, NULL,
2392  ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2393  curtime, capacity, capacity - freecapacity);
2394 
2395  for( i = 0; i <= j; ++i )
2396  {
2397  if( startsolvalues[i] + durations[startindices[i]] > curtime )
2398  {
2399  SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2400  SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2401  demands[startindices[i]]);
2402  }
2403  }
2404  }
2405  break;
2406  }
2407  } /*lint --e{850}*/
2408 
2409  /* update constraint violation in solution */
2410  if( sol != NULL )
2411  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
2412 
2413  /* free all buffer arrays */
2414  SCIPfreeBufferArray(scip, &endindices);
2415  SCIPfreeBufferArray(scip, &startindices);
2416  SCIPfreeBufferArray(scip, &endsolvalues);
2417  SCIPfreeBufferArray(scip, &startsolvalues);
2418 
2419  return SCIP_OKAY;
2420 }
2421 
2422 /** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2423  * least zero or not. If not (*violated) is set to TRUE
2424  */
2425 static
2427  SCIP* scip, /**< SCIP data structure */
2428  SCIP_CONS* cons, /**< constraint to be checked */
2429  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2430  SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2431  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2432  )
2433 {
2434  SCIP_CONSDATA* consdata;
2435 
2436  assert(scip != NULL);
2437  assert(cons != NULL);
2438  assert(violated != NULL);
2439 
2440  SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2441 
2442  consdata = SCIPconsGetData(cons);
2443  assert(consdata != NULL);
2444 
2445  /* check the cumulative condition */
2446  SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2447  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2448  violated, cons, printreason) );
2449 
2450  return SCIP_OKAY;
2451 }
2452 
2453 /**@} */
2454 
2455 /**@name Conflict analysis
2456  *
2457  * @{
2458  */
2459 
2460 /** resolves the propagation of the core time algorithm */
2461 static
2463  SCIP* scip, /**< SCIP data structure */
2464  int nvars, /**< number of start time variables (activities) */
2465  SCIP_VAR** vars, /**< array of start time variables */
2466  int* durations, /**< array of durations */
2467  int* demands, /**< array of demands */
2468  int capacity, /**< cumulative capacity */
2469  int hmin, /**< left bound of time axis to be considered (including hmin) */
2470  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2471  SCIP_VAR* infervar, /**< inference variable */
2472  int inferdemand, /**< demand of the inference variable */
2473  int inferpeak, /**< time point which causes the propagation */
2474  int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2475  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2476  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2477  int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2478  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2479  )
2480 {
2481  SCIP_VAR* var;
2482  SCIP_Bool* reported;
2483  int duration;
2484  int maxlst;
2485  int minect;
2486  int ect;
2487  int lst;
2488  int j;
2489 
2490  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
2491 
2492  SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2493  SCIPvarGetName(infervar), inferdemand, inferpeak);
2494  assert(nvars > 0);
2495 
2496  /* adjusted capacity */
2497  capacity -= inferdemand;
2498  maxlst = INT_MIN;
2499  minect = INT_MAX;
2500 
2501  SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2502  BMSclearMemoryArray(reported, nvars);
2503 
2504  /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2505  * inference peak and those where the current conflict bounds provide a core at the inference peak
2506  */
2507  for( j = 0; j < nvars && capacity >= 0; ++j )
2508  {
2509  var = vars[j];
2510  assert(var != NULL);
2511 
2512  /* skip inference variable */
2513  if( var == infervar )
2514  continue;
2515 
2516  duration = durations[j];
2517  assert(duration > 0);
2518 
2519  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2520  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2521  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2522  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2523  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2524 
2525  SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2527  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2528 
2529  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2530  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2531 
2532  /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2533  * that job without adding it the explanation
2534  */
2535  if( inferpeak < ect && lst <= inferpeak )
2536  {
2537  capacity -= demands[j];
2538  reported[j] = TRUE;
2539 
2540  maxlst = MAX(maxlst, lst);
2541  minect = MIN(minect, ect);
2542  assert(maxlst < minect);
2543 
2544  if( explanation != NULL )
2545  explanation[j] = TRUE;
2546 
2547  continue;
2548  }
2549 
2550  /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2551  * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2552  * not part of the conflict yet we get the global bounds back.
2553  */
2554  ect = SCIPconvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2555  lst = SCIPconvertRealToInt(scip, SCIPgetConflictVarUb(scip, var));
2556 
2557  /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2558  * of that job without and collect the job as part of the explanation
2559  *
2560  * @note we do not need to reported that job to SCIP since the required bounds are already reported
2561  */
2562  if( inferpeak < ect && lst <= inferpeak )
2563  {
2564  capacity -= demands[j];
2565  reported[j] = TRUE;
2566 
2567  maxlst = MAX(maxlst, lst);
2568  minect = MIN(minect, ect);
2569  assert(maxlst < minect);
2570 
2571  if( explanation != NULL )
2572  explanation[j] = TRUE;
2573  }
2574  }
2575 
2576  if( capacity >= 0 )
2577  {
2578  int* cands;
2579  int* canddemands;
2580  int ncands;
2581  int c;
2582 
2583  SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2584  SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2585  ncands = 0;
2586 
2587  /* collect all cores of the variables which lay in the considered time window except the inference variable */
2588  for( j = 0; j < nvars; ++j )
2589  {
2590  var = vars[j];
2591  assert(var != NULL);
2592 
2593  /* skip inference variable */
2594  if( var == infervar || reported[j] )
2595  continue;
2596 
2597  duration = durations[j];
2598  assert(duration > 0);
2599 
2600  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2601  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2602  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2603  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2604  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2605 
2606  /* collect local core information */
2607  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2608  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2609 
2610  SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2611  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2612  SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2613 
2614  /* check if the inference peak is part of the core */
2615  if( inferpeak < ect && lst <= inferpeak )
2616  {
2617  cands[ncands] = j;
2618  canddemands[ncands] = demands[j];
2619  ncands++;
2620 
2621  capacity -= demands[j];
2622  }
2623  }
2624 
2625  /* sort candidates indices w.r.t. their demands */
2626  SCIPsortDownIntInt(canddemands, cands, ncands);
2627 
2628  assert(capacity < 0);
2629  assert(ncands > 0);
2630 
2631  /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2632  while( capacity + canddemands[ncands-1] < 0 )
2633  {
2634  ncands--;
2635  capacity += canddemands[ncands];
2636  assert(ncands > 0);
2637  }
2638 
2639  /* compute the size (number of time steps) of the job cores */
2640  for( c = 0; c < ncands; ++c )
2641  {
2642  var = vars[cands[c]];
2643  assert(var != NULL);
2644 
2645  duration = durations[cands[c]];
2646 
2647  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2648  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2649 
2650  maxlst = MAX(maxlst, lst);
2651  minect = MIN(minect, ect);
2652  assert(maxlst < minect);
2653  }
2654 
2655  SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2656  assert(inferpeak >= maxlst);
2657  assert(inferpeak < minect);
2658 
2659  /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2660  if( relaxedpeak < inferpeak )
2661  {
2662  inferpeak = MAX(maxlst, relaxedpeak);
2663  }
2664  else if( relaxedpeak > inferpeak )
2665  {
2666  inferpeak = MIN(minect-1, relaxedpeak);
2667  }
2668  assert(inferpeak >= hmin);
2669  assert(inferpeak < hmax);
2670  assert(inferpeak >= maxlst);
2671  assert(inferpeak < minect);
2672 
2673  /* post all necessary bound changes */
2674  for( c = 0; c < ncands; ++c )
2675  {
2676  var = vars[cands[c]];
2677  assert(var != NULL);
2678 
2679  if( usebdwidening )
2680  {
2681  duration = durations[cands[c]];
2682 
2683  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2684  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2685  }
2686  else
2687  {
2688  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2689  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2690  }
2691 
2692  if( explanation != NULL )
2693  explanation[cands[c]] = TRUE;
2694  }
2695 
2696  SCIPfreeBufferArray(scip, &canddemands);
2697  SCIPfreeBufferArray(scip, &cands);
2698  }
2699 
2700  SCIPfreeBufferArray(scip, &reported);
2701 
2702  if( provedpeak != NULL )
2703  *provedpeak = inferpeak;
2704 
2705  return SCIP_OKAY;
2706 }
2707 
2708 #if 0
2709 /** repropagation of edge finding algorithm simplified version from Petr Vilim only a small subset is reported such that
2710  * energy in total and for bound change is enough
2711  */
2712 static
2713 SCIP_RETCODE resolvePropagationEdgeFinding(
2714  SCIP* scip, /**< SCIP data structure */
2715  int nvars, /**< number of start time variables (activities) */
2716  SCIP_VAR** vars, /**< array of start time variables */
2717  int* durations, /**< array of durations */
2718  int hmin, /**< left bound of time axis to be considered (including hmin) */
2719  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2720  SCIP_VAR* infervar, /**< variable whose bound change is to be explained */
2721  INFERINFO inferinfo, /**< inference info containing position of correct bdchgids */
2722  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2723  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2724  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2725  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2726  )
2727 {
2728  int est;
2729  int lct;
2730  int j;
2731 
2732  /* ???????????????????? do bound widening */
2733 
2734  assert(scip != NULL);
2735  assert(nvars > 0);
2736  assert(inferInfoGetProprule(inferinfo) == PROPRULE_2_EDGEFINDING);
2737 
2738  SCIPdebugMsg(scip, "repropagate edge-finding with short reasons for variable <%s>\n", SCIPvarGetName(infervar));
2739 
2740  if( boundtype == SCIP_BOUNDTYPE_LOWER )
2741  {
2742  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
2743  }
2744  else
2745  {
2746  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
2747  }
2748 
2749  est = inferInfoGetData1(inferinfo);
2750  lct = inferInfoGetData2(inferinfo);
2751  assert(est < lct);
2752 
2753  /* collect the energies of all variables in [est_omega, lct_omega] */
2754  for( j = 0; j < nvars; ++j )
2755  {
2756  SCIP_VAR* var;
2757  SCIP_Bool left;
2758  SCIP_Bool right;
2759  int duration;
2760  int lb;
2761  int ub;
2762 
2763  var = vars[j];
2764  assert(var != NULL);
2765 
2766  if( var == infervar )
2767  {
2768  if( explanation != NULL )
2769  explanation[j] = TRUE;
2770 
2771  continue;
2772  }
2773 
2774  lb = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
2775  ub = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2776 
2777  duration = durations[j];
2778  assert(duration > 0);
2779 
2780  /* in case the earliest start time is equal to hmin we have to also consider the jobs which run in that region
2781  * since we use adjusted jobs during the propagation
2782  */
2783  left = (est == hmin && lb + duration > hmin) || lb >= est;
2784 
2785  /* in case the latest completion time is equal to hmax we have to also consider the jobs which run in that region
2786  * since we use adjusted jobs during the propagation
2787  */
2788  right = (lct == hmax && ub < hmax) || ub + duration <= lct;
2789 
2790  /* store all jobs running in [est_omega; lct_omega] */
2791  if( left && right )
2792  {
2793  /* check if bound widening should be used */
2794  if( usebdwidening )
2795  {
2796  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(lct - duration)) );
2797  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(est)) );
2798  }
2799  else
2800  {
2801  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2802  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2803  }
2804 
2805  if( explanation != NULL )
2806  explanation[j] = TRUE;
2807  }
2808  }
2809 
2810  return SCIP_OKAY;
2811 }
2812 #endif
2813 
2814 /** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2815 static
2816 int computeOverlap(
2817  int begin, /**< begin of the times interval */
2818  int end, /**< end of time interval */
2819  int est, /**< earliest start time */
2820  int lst, /**< latest start time */
2821  int duration /**< duration of the job */
2822  )
2823 {
2824  int left;
2825  int right;
2826  int ect;
2827  int lct;
2828 
2829  ect = est + duration;
2830  lct = lst + duration;
2831 
2832  /* check if job runs completely within [begin,end) */
2833  if( lct <= end && est >= begin )
2834  return duration;
2835 
2836  assert(lst <= end && ect >= begin);
2837 
2838  left = ect - begin;
2839  assert(left > 0);
2840 
2841  right = end - lst;
2842  assert(right > 0);
2843 
2844  return MIN3(left, right, end - begin);
2845 }
2846 
2847 /** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2848  * reason
2849  *
2850  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2851  */
2852 static
2854  SCIP* scip, /**< SCIP data structure */
2855  int nvars, /**< number of start time variables (activities) */
2856  SCIP_VAR** vars, /**< array of start time variables */
2857  int* durations, /**< array of durations */
2858  int* demands, /**< array of demands */
2859  int capacity, /**< capacity of the cumulative condition */
2860  int begin, /**< begin of the time window */
2861  int end, /**< end of the time window */
2862  SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2863  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2864  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2865  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2866  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2867  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2868  )
2869 {
2870  int* locenergies;
2871  int* overlaps;
2872  int* idxs;
2873 
2874  int requiredenergy;
2875  int v;
2876 
2877  SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2878  SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2879  SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2880 
2881  /* energy which needs be explained */
2882  requiredenergy = (end - begin) * capacity;
2883 
2884  SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %d)\n", begin, end, capacity, requiredenergy);
2885 
2886  /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2887  * takes
2888  */
2889  for( v = 0; v < nvars; ++v )
2890  {
2891  SCIP_VAR* var;
2892  int glbenergy;
2893  int duration;
2894  int demand;
2895  int est;
2896  int lst;
2897 
2898  var = vars[v];
2899  assert(var != NULL);
2900 
2901  locenergies[v] = 0;
2902  overlaps[v] = 0;
2903  idxs[v] = v;
2904 
2905  demand = demands[v];
2906  assert(demand > 0);
2907 
2908  duration = durations[v];
2909  assert(duration > 0);
2910 
2911  /* check if the variable equals the inference variable (the one which was propagated) */
2912  if( infervar == var )
2913  {
2914  int overlap;
2915  int right;
2916  int left;
2917 
2918  assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2919 
2920  SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2921  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2922  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2923 
2924  /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2925  * which is necessary from the inference variable
2926  */
2927  if( boundtype == SCIP_BOUNDTYPE_UPPER )
2928  {
2929  int lct;
2930 
2931  /* get the latest start time of the infer start time variable before the propagation took place */
2932  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2933 
2934  /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2935  * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2936  * scheduled w.r.t. its latest start time
2937  */
2938  assert(lst < end);
2939 
2940  /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2941  * interval (before the propagation)
2942  */
2943  right = MIN3(end - lst, end - begin, duration);
2944 
2945  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2946  assert(right > 0);
2947 
2948  lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2949  assert(begin <= lct);
2950  assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
2951 
2952  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2953  left = MIN(lct - begin + 1, end - begin);
2954  assert(left > 0);
2955 
2956  /* compute the minimum overlap; */
2957  overlap = MIN(left, right);
2958  assert(overlap > 0);
2959  assert(overlap <= end - begin);
2960  assert(overlap <= duration);
2961 
2962  if( usebdwidening )
2963  {
2964  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2965  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2966  }
2967  else
2968  {
2969  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2970  }
2971  }
2972  else
2973  {
2974  int ect;
2975 
2976  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2977 
2978  /* get the earliest completion time of the infer start time variable before the propagation took place */
2979  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2980 
2981  /* the earliest start time of the inference start time variable before the propagation needs to be larger as
2982  * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
2983  * the job is scheduled w.r.t. its earliest start time
2984  */
2985  assert(ect > begin);
2986 
2987  /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
2988  * interval (before the propagation)
2989  */
2990  left = MIN3(ect - begin, end - begin, duration);
2991 
2992  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2993  assert(left > 0);
2994 
2995  est = SCIPconvertRealToInt(scip, relaxedbd);
2996  assert(end >= est);
2997  assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
2998 
2999  /* compute the overlap of the job after the propagation but considering the relaxed bound */
3000  right = MIN(end - est + 1, end - begin);
3001  assert(right > 0);
3002 
3003  /* compute the minimum overlap */
3004  overlap = MIN(left, right);
3005  assert(overlap > 0);
3006  assert(overlap <= end - begin);
3007  assert(overlap <= duration);
3008 
3009  if( usebdwidening )
3010  {
3011  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
3012  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
3013  }
3014  else
3015  {
3016  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
3017  }
3018  }
3019 
3020  /* subtract the amount of energy which is available due to the overlap of the inference start time */
3021  requiredenergy -= overlap * demand;
3022 
3023  if( explanation != NULL )
3024  explanation[v] = TRUE;
3025 
3026  continue;
3027  }
3028 
3029  /* global time points */
3030  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
3031  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
3032 
3033  glbenergy = 0;
3034 
3035  /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
3036  * time window
3037  */
3038  if( est + duration > begin && lst < end )
3039  {
3040  /* evaluated global contribution */
3041  glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
3042 
3043  /* remove the globally available energy form the required energy */
3044  requiredenergy -= glbenergy;
3045 
3046  if( explanation != NULL )
3047  explanation[v] = TRUE;
3048  }
3049 
3050  /* local time points */
3051  est = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
3052  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
3053 
3054  /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3055  * time window
3056  */
3057  if( est + duration > begin && lst < end )
3058  {
3059  overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3060 
3061  /* evaluated additionally local energy contribution */
3062  locenergies[v] = overlaps[v] * demand - glbenergy;
3063  assert(locenergies[v] >= 0);
3064  }
3065  }
3066 
3067  /* sort the variable contributions w.r.t. additional local energy contributions */
3068  SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3069 
3070  /* add local energy contributions until an overload is implied */
3071  for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3072  {
3073  SCIP_VAR* var;
3074  int duration;
3075  int overlap;
3076  int relaxlb;
3077  int relaxub;
3078  int idx;
3079 
3080  idx = idxs[v];
3081  assert(idx >= 0 && idx < nvars);
3082 
3083  var = vars[idx];
3084  assert(var != NULL);
3085  assert(var != infervar);
3086 
3087  duration = durations[idx];
3088  assert(duration > 0);
3089 
3090  overlap = overlaps[v];
3091  assert(overlap > 0);
3092 
3093  requiredenergy -= locenergies[v];
3094 
3095  if( requiredenergy < -1 )
3096  {
3097  int demand;
3098 
3099  demand = demands[idx];
3100  assert(demand > 0);
3101 
3102  overlap += (int)((requiredenergy + 1) / demand);
3103 
3104 #ifndef NDEBUG
3105  requiredenergy += locenergies[v];
3106  requiredenergy -= overlap * demand;
3107  assert(requiredenergy < 0);
3108 #endif
3109  }
3110  assert(overlap > 0);
3111 
3112  relaxlb = begin - duration + overlap;
3113  relaxub = end - overlap;
3114 
3115  SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3116  SCIPvarGetName(var),
3119  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var),
3120  relaxlb, relaxub, demands[idx], duration);
3121 
3122  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3123  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3124 
3125  if( explanation != NULL )
3126  explanation[idx] = TRUE;
3127  }
3128 
3129  assert(requiredenergy < 0);
3130 
3131  SCIPfreeBufferArray(scip, &idxs);
3132  SCIPfreeBufferArray(scip, &overlaps);
3133  SCIPfreeBufferArray(scip, &locenergies);
3134 
3135  return SCIP_OKAY;
3136 }
3137 
3138 /** resolve propagation w.r.t. the cumulative condition */
3139 static
3141  SCIP* scip, /**< SCIP data structure */
3142  int nvars, /**< number of start time variables (activities) */
3143  SCIP_VAR** vars, /**< array of start time variables */
3144  int* durations, /**< array of durations */
3145  int* demands, /**< array of demands */
3146  int capacity, /**< cumulative capacity */
3147  int hmin, /**< left bound of time axis to be considered (including hmin) */
3148  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3149  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3150  INFERINFO inferinfo, /**< the user information */
3151  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3152  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3153  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3154  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3155  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3156  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3157  )
3158 {
3159  switch( inferInfoGetProprule(inferinfo) )
3160  {
3161  case PROPRULE_1_CORETIMES:
3162  {
3163  int inferdemand;
3164  int inferduration;
3165  int inferpos;
3166  int inferpeak;
3167  int relaxedpeak;
3168  int provedpeak;
3169 
3170  /* get the position of the inferred variable in the vars array */
3171  inferpos = inferInfoGetData1(inferinfo);
3172  if( inferpos >= nvars || vars[inferpos] != infervar )
3173  {
3174  /* find inference variable in constraint */
3175  for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3176  {}
3177  }
3178  assert(inferpos < nvars);
3179  assert(vars[inferpos] == infervar);
3180 
3181  inferdemand = demands[inferpos];
3182  inferduration = durations[inferpos];
3183 
3184  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3185  {
3186  /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3187  * the inference variable
3188  */
3189  assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
3190 
3191  SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3192  SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
3193  SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3194 
3195  /* get the inference peak that the time point which lead to the that propagtion */
3196  inferpeak = inferInfoGetData2(inferinfo);
3197  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3198  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3199  */
3200  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3201  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) + inferduration;
3202 
3203  /* make sure that the relaxed peak is part of the effective horizon */
3204  relaxedpeak = MIN(relaxedpeak, hmax-1);
3205 
3206  /* make sure that relaxed peak is not larger than the infer peak
3207  *
3208  * This can happen in case the variable is not an active variable!
3209  */
3210  relaxedpeak = MAX(relaxedpeak, inferpeak);
3211  assert(relaxedpeak >= inferpeak);
3212  assert(relaxedpeak >= hmin);
3213  }
3214  else
3215  {
3216  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3217 
3218  SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3219  SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
3220  SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3221 
3222  /* get the time interval where the job could not be scheduled */
3223  inferpeak = inferInfoGetData2(inferinfo);
3224  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3225  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3226  */
3227  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3228  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) - 1;
3229 
3230  /* make sure that the relaxed peak is part of the effective horizon */
3231  relaxedpeak = MAX(relaxedpeak, hmin);
3232 
3233  /* make sure that relaxed peak is not larger than the infer peak
3234  *
3235  * This can happen in case the variable is not an active variable!
3236  */
3237  relaxedpeak = MIN(relaxedpeak, inferpeak);
3238  assert(relaxedpeak < hmax);
3239  }
3240 
3241  /* resolves the propagation of the core time algorithm */
3242  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3243  infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3244 
3245  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3246  {
3247  if( usebdwidening )
3248  {
3249  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3250  }
3251  else
3252  {
3253  /* old upper bound of variable itself is part of the explanation */
3254  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3255  }
3256  }
3257  else
3258  {
3259  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3260 
3261  if( usebdwidening )
3262  {
3263  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3264  }
3265  else
3266  {
3267  /* old lower bound of variable itself is part of the explanation */
3268  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3269  }
3270  }
3271 
3272  if( explanation != NULL )
3273  explanation[inferpos] = TRUE;
3274 
3275  break;
3276  }
3278  case PROPRULE_3_TTEF:
3279  {
3280  int begin;
3281  int end;
3282 
3283  begin = inferInfoGetData1(inferinfo);
3284  end = inferInfoGetData2(inferinfo);
3285  assert(begin < end);
3286 
3287  begin = MAX(begin, hmin);
3288  end = MIN(end, hmax);
3289 
3290  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3291  begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3292 
3293  break;
3294  }
3295 
3296  default:
3297  SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3298  SCIPABORT();
3299  return SCIP_INVALIDDATA; /*lint !e527*/
3300  }
3301 
3302  (*result) = SCIP_SUCCESS;
3303 
3304  return SCIP_OKAY;
3305 }
3306 
3307 /**@} */
3308 
3309 
3310 /**@name Enforcement methods
3311  *
3312  * @{
3313  */
3314 
3315 /** apply all fixings which are given by the alternative bounds */
3316 static
3318  SCIP* scip, /**< SCIP data structure */
3319  SCIP_VAR** vars, /**< array of active variables */
3320  int nvars, /**< number of active variables */
3321  int* alternativelbs, /**< alternative lower bounds */
3322  int* alternativeubs, /**< alternative lower bounds */
3323  int* downlocks, /**< number of constraints with down lock participating by the computation */
3324  int* uplocks, /**< number of constraints with up lock participating by the computation */
3325  SCIP_Bool* branched /**< pointer to store if a branching was applied */
3326  )
3327 {
3328  int v;
3329 
3330  for( v = 0; v < nvars; ++v )
3331  {
3332  SCIP_VAR* var;
3333  SCIP_Real objval;
3334 
3335  var = vars[v];
3336  assert(var != NULL);
3337 
3338  objval = SCIPvarGetObj(var);
3339 
3340  if( SCIPvarGetNLocksDown(var) == downlocks[v] && !SCIPisNegative(scip, objval) )
3341  {
3342  int ub;
3343 
3344  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3345 
3346  if( alternativelbs[v] <= ub )
3347  {
3348  SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3349  (*branched) = TRUE;
3350 
3351  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3352  SCIPvarGetLbLocal(var), alternativelbs[v]);
3353 
3354  return SCIP_OKAY;
3355  }
3356  }
3357 
3358  if( SCIPvarGetNLocksUp(var) == uplocks[v] && !SCIPisPositive(scip, objval) )
3359  {
3360  int lb;
3361 
3362  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3363 
3364  if( alternativeubs[v] >= lb )
3365  {
3366  SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3367  (*branched) = TRUE;
3368 
3369  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3370  alternativeubs[v], SCIPvarGetUbLocal(var));
3371 
3372  return SCIP_OKAY;
3373  }
3374  }
3375  }
3376 
3377  return SCIP_OKAY;
3378 }
3379 
3380 /** remove the capacity requirments for all job which start at the curtime */
3381 static
3383  SCIP_CONSDATA* consdata, /**< constraint data */
3384  int curtime, /**< current point in time */
3385  int* starttimes, /**< array of start times */
3386  int* startindices, /**< permutation with respect to the start times */
3387  int* freecapacity, /**< pointer to store the resulting free capacity */
3388  int* idx, /**< pointer to index in start time array */
3389  int nvars /**< number of vars in array of starttimes and startindices */
3390  )
3391 {
3392 
3393 #if defined SCIP_DEBUG && !defined NDEBUG
3394  int oldidx;
3395 
3396  assert(idx != NULL);
3397  oldidx = *idx;
3398 #else
3399  assert(idx != NULL);
3400 #endif
3401 
3402  assert(starttimes != NULL);
3403  assert(starttimes != NULL);
3404  assert(freecapacity != NULL);
3405  assert(starttimes[*idx] == curtime);
3406  assert(consdata->demands != NULL);
3407  assert(freecapacity != idx);
3408 
3409  /* subtract all capacity needed up to this point */
3410  (*freecapacity) -= consdata->demands[startindices[*idx]];
3411 
3412  while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3413  {
3414  ++(*idx);
3415  (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3416  assert(freecapacity != idx);
3417  }
3418 #ifdef SCIP_DEBUG
3419  assert(oldidx <= *idx);
3420 #endif
3421 }
3422 
3423 /** add the capacity requirments for all job which end at the curtime */
3424 static
3425 void addEndingJobDemands(
3426  SCIP_CONSDATA* consdata, /**< constraint data */
3427  int curtime, /**< current point in time */
3428  int* endtimes, /**< array of end times */
3429  int* endindices, /**< permutation with rspect to the end times */
3430  int* freecapacity, /**< pointer to store the resulting free capacity */
3431  int* idx, /**< pointer to index in end time array */
3432  int nvars /**< number of vars in array of starttimes and startindices */
3433  )
3434 {
3435 #if defined SCIP_DEBUG && !defined NDEBUG
3436  int oldidx;
3437  oldidx = *idx;
3438 #endif
3439 
3440  /* free all capacity usages of jobs the are no longer running */
3441  while( endtimes[*idx] <= curtime && *idx < nvars)
3442  {
3443  (*freecapacity) += consdata->demands[endindices[*idx]];
3444  ++(*idx);
3445  }
3446 
3447 #ifdef SCIP_DEBUG
3448  assert(oldidx <= *idx);
3449 #endif
3450 }
3451 
3452 /** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3453 static
3455  SCIP* scip, /**< SCIP data structure */
3456  SCIP_CONSDATA* consdata, /**< constraint handler data */
3457  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3458  int* timepoint /**< pointer to store the time point of the peak */
3459  )
3460 {
3461  int* starttimes; /* stores when each job is starting */
3462  int* endtimes; /* stores when each job ends */
3463  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3464  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3465 
3466  int nvars; /* number of activities for this constraint */
3467  int freecapacity; /* remaining capacity */
3468  int curtime; /* point in time which we are just checking */
3469  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3470 
3471  int hmin;
3472  int hmax;
3473 
3474  int j;
3475 
3476  assert(consdata != NULL);
3477 
3478  nvars = consdata->nvars;
3479  assert(nvars > 0);
3480 
3481  *timepoint = consdata->hmax;
3482 
3483  assert(consdata->vars != NULL);
3484 
3485  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3486  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3487  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3488  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3489 
3490  /* create event point arrays */
3491  createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3492  starttimes, endtimes, startindices, endindices);
3493 
3494  endindex = 0;
3495  freecapacity = consdata->capacity;
3496  hmin = consdata->hmin;
3497  hmax = consdata->hmax;
3498 
3499  /* check each startpoint of a job whether the capacity is kept or not */
3500  for( j = 0; j < nvars; ++j )
3501  {
3502  curtime = starttimes[j];
3503  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3504 
3505  if( curtime >= hmax )
3506  break;
3507 
3508  /* remove the capacity requirments for all job which start at the curtime */
3509  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3510 
3511  /* add the capacity requirments for all job which end at the curtime */
3512  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3513 
3514  assert(freecapacity <= consdata->capacity);
3515  assert(endindex <= nvars);
3516 
3517  /* endindex - points to the next job which will finish */
3518  /* j - points to the last job that has been released */
3519 
3520  /* if free capacity is smaller than zero, then add branching candidates */
3521  if( freecapacity < 0 && curtime >= hmin )
3522  {
3523  *timepoint = curtime;
3524  break;
3525  }
3526  } /*lint --e{850}*/
3527 
3528  /* free all buffer arrays */
3529  SCIPfreeBufferArray(scip, &endindices);
3530  SCIPfreeBufferArray(scip, &startindices);
3531  SCIPfreeBufferArray(scip, &endtimes);
3532  SCIPfreeBufferArray(scip, &starttimes);
3533 
3534  return SCIP_OKAY;
3535 }
3536 
3537 /** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3538 static
3540  SCIP* scip, /**< SCIP data structure */
3541  SCIP_CONS** conss, /**< constraints to be processed */
3542  int nconss, /**< number of constraints */
3543  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3544  int* nbranchcands /**< pointer to store the number of branching variables */
3545  )
3546 {
3547  SCIP_HASHTABLE* collectedvars;
3548  int c;
3549 
3550  assert(scip != NULL);
3551  assert(conss != NULL);
3552 
3553  /* create a hash table */
3554  SCIP_CALL( SCIPhashtableCreate(&collectedvars, SCIPblkmem(scip), SCIPgetNVars(scip),
3555  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3556 
3557  assert(scip != NULL);
3558  assert(conss != NULL);
3559 
3560  for( c = 0; c < nconss; ++c )
3561  {
3562  SCIP_CONS* cons;
3563  SCIP_CONSDATA* consdata;
3564 
3565  int curtime;
3566  int j;
3567 
3568  cons = conss[c];
3569  assert(cons != NULL);
3570 
3571  if( !SCIPconsIsActive(cons) )
3572  continue;
3573 
3574  consdata = SCIPconsGetData(cons);
3575  assert(consdata != NULL);
3576 
3577  /* get point in time when capacity is exceeded */
3578  SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3579 
3580  if( curtime < consdata->hmin || curtime >= consdata->hmax )
3581  continue;
3582 
3583  /* report all variables that are running at that point in time */
3584  for( j = 0; j < consdata->nvars; ++j )
3585  {
3586  SCIP_VAR* var;
3587  int lb;
3588  int ub;
3589 
3590  var = consdata->vars[j];
3591  assert(var != NULL);
3592 
3593  /* check if the variable was already added */
3594  if( SCIPhashtableExists(collectedvars, (void*)var) )
3595  continue;
3596 
3597  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3598  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3599 
3600  if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3601  {
3602  SCIP_Real solval;
3603  SCIP_Real score;
3604 
3605  solval = SCIPgetSolVal(scip, sol, var);
3606  score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3607 
3608  SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3609  SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3610  (*nbranchcands)++;
3611 
3612  SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3613  }
3614  }
3615  }
3616 
3617  SCIPhashtableFree(&collectedvars);
3618 
3619  SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3620 
3621  return SCIP_OKAY;
3622 }
3623 
3624 /** enforcement of an LP, pseudo, or relaxation solution */
3625 static
3627  SCIP* scip, /**< SCIP data structure */
3628  SCIP_CONS** conss, /**< constraints to be processed */
3629  int nconss, /**< number of constraints */
3630  SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
3631  SCIP_Bool branch, /**< should branching candidates be collected */
3632  SCIP_RESULT* result /**< pointer to store the result */
3633  )
3634 {
3635  if( branch )
3636  {
3637  int nbranchcands;
3638 
3639  nbranchcands = 0;
3640  SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3641 
3642  if( nbranchcands > 0 )
3643  (*result) = SCIP_INFEASIBLE;
3644  }
3645  else
3646  {
3647  SCIP_Bool violated;
3648  int c;
3649 
3650  violated = FALSE;
3651 
3652  /* first check if a constraints is violated */
3653  for( c = 0; c < nconss && !violated; ++c )
3654  {
3655  SCIP_CONS* cons;
3656 
3657  cons = conss[c];
3658  assert(cons != NULL);
3659 
3660  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3661  }
3662 
3663  if( violated )
3664  (*result) = SCIP_INFEASIBLE;
3665  }
3666 
3667  return SCIP_OKAY;
3668 }
3669 
3670 /**@} */
3671 
3672 /**@name Propagation
3673  *
3674  * @{
3675  */
3676 
3677 /** check if cumulative constraint is independently of all other constraints */
3678 static
3680  SCIP* scip, /**< SCIP data structure */
3681  SCIP_CONS* cons /**< cumulative constraint */
3682  )
3683 {
3684  SCIP_CONSDATA* consdata;
3685  SCIP_VAR** vars;
3686  SCIP_Bool* downlocks;
3687  SCIP_Bool* uplocks;
3688  int nvars;
3689  int v;
3690 
3691  consdata = SCIPconsGetData(cons);
3692  assert(consdata != NULL);
3693 
3694  nvars = consdata->nvars;
3695  vars = consdata->vars;
3696  downlocks = consdata->downlocks;
3697  uplocks = consdata->uplocks;
3698 
3699  /* check if the cumulative constraint has the only locks on the involved variables */
3700  for( v = 0; v < nvars; ++v )
3701  {
3702  SCIP_VAR* var;
3703 
3704  var = vars[v];
3705  assert(var != NULL);
3706 
3707  if( SCIPvarGetNLocksDown(var) > (int)downlocks[v] || SCIPvarGetNLocksUp(var) > (int)uplocks[v] )
3708  return FALSE;
3709  }
3710 
3711  return TRUE;
3712 }
3713 
3714 /** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3715  * (dual reductions)
3716  */
3717 static
3719  SCIP* scip, /**< SCIP data structure */
3720  SCIP_CONS* cons, /**< cumulative constraint */
3721  SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3722  int* nchgbds, /**< pointer to store the number changed variable bounds */
3723  int* nfixedvars, /**< pointer to count number of fixings */
3724  int* ndelconss, /**< pointer to count number of deleted constraints */
3725  SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3726  SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3727  )
3728 {
3729  SCIP_CONSDATA* consdata;
3730  SCIP_VAR** vars;
3731  SCIP_Real* objvals;
3732  SCIP_Real* lbs;
3733  SCIP_Real* ubs;
3734  SCIP_Real timelimit;
3735  SCIP_Real memorylimit;
3736  SCIP_Bool solved;
3737  SCIP_Bool error;
3738 
3739  int ncheckconss;
3740  int nvars;
3741  int v;
3742 
3743  assert(scip != NULL);
3744  assert(!SCIPconsIsModifiable(cons));
3745  assert(SCIPgetNConss(scip) > 0);
3746 
3747  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3748  * would/could end in an implication which can lead to cutoff of the/all optimal solution
3749  */
3750  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
3751  return SCIP_OKAY;
3752 
3753  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3754  * use the locks to decide for a dual reduction using this constraint;
3755  */
3756  if( !SCIPconsIsChecked(cons) )
3757  return SCIP_OKAY;
3758 
3759  ncheckconss = SCIPgetNCheckConss(scip);
3760 
3761  /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3762  * presolved problem do nothing execpt to change the parameter settings
3763  */
3764  if( ncheckconss == 1 )
3765  {
3766  /* shrink the minimal maximum value for the conflict length */
3767  SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3768 
3769  /* use only first unique implication point */
3770  SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3771 
3772  /* do not use reconversion conflicts */
3773  SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3774 
3775  /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3776  SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3777 
3778  /* increase the number of conflicts which induce a restart */
3779  SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3780 
3781  /* weight the variable which made into a conflict */
3782  SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3783 
3784  /* do not check pseudo solution (for performance reasons) */
3785  SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3786 
3787  /* use value based history to detect a reasonable branching point */
3788  SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3789 
3790  /* turn of LP relaxation */
3791  SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3792 
3793  /* prefer the down branch in case the value based history does not suggest something */
3794  SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3795 
3796  /* accept any bound change */
3797  SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3798 
3799  /* allow for at most 10 restart, after that the value based history should be reliable */
3800  SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3801 
3802  /* set priority for depth first search to highest possible value */
3803  SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3804 
3805  return SCIP_OKAY;
3806  }
3807 
3808  consdata = SCIPconsGetData(cons);
3809  assert(consdata != NULL);
3810 
3811  /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3812  * fail on the first place
3813  */
3814  if( consdata->triedsolving )
3815  return SCIP_OKAY;
3816 
3817  /* check if constraint is independently */
3818  if( !isConsIndependently(scip, cons) )
3819  return SCIP_OKAY;
3820 
3821  /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3822  * constraint is deleted; otherwise, we want to ensure that we do not try that again
3823  */
3824  consdata->triedsolving = TRUE;
3825 
3826  SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3827  SCIPconsGetName(cons), SCIPgetNVars(scip), SCIPgetNConss(scip));
3828  SCIPdebugPrintCons(scip, cons, NULL);
3829 
3830  nvars = consdata->nvars;
3831  vars = consdata->vars;
3832 
3833  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3834  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3835  SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3836 
3837  for( v = 0; v < nvars; ++v )
3838  {
3839  SCIP_VAR* var;
3840 
3841  /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3842  * array
3843  */
3844  var = vars[v];
3845  assert(var != NULL);
3846 
3847  lbs[v] = SCIPvarGetLbLocal(var);
3848  ubs[v] = SCIPvarGetUbLocal(var);
3849 
3850  objvals[v] = SCIPvarGetObj(var);
3851  }
3852 
3853  /* check whether there is enough time and memory left */
3854  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3855  if( !SCIPisInfinity(scip, timelimit) )
3856  timelimit -= SCIPgetSolvingTime(scip);
3857  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3858 
3859  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3860  if( !SCIPisInfinity(scip, memorylimit) )
3861  {
3862  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3863  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3864  }
3865 
3866  /* solve the cumulative condition separately */
3867  SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3868  consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3869 
3870  if( !(*cutoff) && !(*unbounded) && !error )
3871  {
3872  SCIP_Bool infeasible;
3873  SCIP_Bool tightened;
3874  SCIP_Bool allfixed;
3875 
3876  allfixed = TRUE;
3877 
3878  for( v = 0; v < nvars; ++v )
3879  {
3880  /* check if variable is fixed */
3881  if( lbs[v] + 0.5 > ubs[v] )
3882  {
3883  SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3884  assert(!infeasible);
3885 
3886  if( tightened )
3887  {
3888  (*nfixedvars)++;
3889  consdata->triedsolving = FALSE;
3890  }
3891  }
3892  else
3893  {
3894  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3895  assert(!infeasible);
3896 
3897  if( tightened )
3898  {
3899  (*nchgbds)++;
3900  consdata->triedsolving = FALSE;
3901  }
3902 
3903  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3904  assert(!infeasible);
3905 
3906  if( tightened )
3907  {
3908  (*nchgbds)++;
3909  consdata->triedsolving = FALSE;
3910  }
3911 
3912  allfixed = FALSE;
3913  }
3914  }
3915 
3916  /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3917  if( allfixed )
3918  {
3919  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3920  (*ndelconss)++;
3921  }
3922  }
3923 
3924  SCIPfreeBufferArray(scip, &objvals);
3925  SCIPfreeBufferArray(scip, &ubs);
3926  SCIPfreeBufferArray(scip, &lbs);
3927 
3928  return SCIP_OKAY;
3929 }
3930 
3931 /** start conflict analysis to analysis the core insertion which is infeasible */
3932 static
3934  SCIP* scip, /**< SCIP data structure */
3935  int nvars, /**< number of start time variables (activities) */
3936  SCIP_VAR** vars, /**< array of start time variables */
3937  int* durations, /**< array of durations */
3938  int* demands, /**< array of demands */
3939  int capacity, /**< cumulative capacity */
3940  int hmin, /**< left bound of time axis to be considered (including hmin) */
3941  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3942  SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3943  int inferduration, /**< duration of the start time variable */
3944  int inferdemand, /**< demand of the start time variable */
3945  int inferpeak, /**< profile preak which causes the infeasibilty */
3946  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3947  SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3948  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3949  )
3950 {
3951  SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3952  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3953  SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3954 
3955  /* initialize conflict analysis if conflict analysis is applicable */
3957  {
3959 
3960  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3961  infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3962 
3963  SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3964 
3965  /* add both bound of the inference variable since these biuld the core which we could not inserted */
3966  if( usebdwidening )
3967  {
3968  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
3969  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
3970  }
3971  else
3972  {
3973  SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
3974  SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
3975  }
3976 
3977  *initialized = TRUE;
3978  }
3979 
3980  return SCIP_OKAY;
3981 }
3982 
3983 /** We are using the core resource profile which contains all core except the one of the start time variable which we
3984  * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
3985  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
3986  * analysis
3987  */
3988 static
3990  SCIP* scip, /**< SCIP data structure */
3991  int nvars, /**< number of start time variables (activities) */
3992  SCIP_VAR** vars, /**< array of start time variables */
3993  int* durations, /**< array of durations */
3994  int* demands, /**< array of demands */
3995  int capacity, /**< cumulative capacity */
3996  int hmin, /**< left bound of time axis to be considered (including hmin) */
3997  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3998  SCIP_CONS* cons, /**< constraint which is propagated */
3999  SCIP_PROFILE* profile, /**< resource profile */
4000  int idx, /**< position of the variable to propagate */
4001  int* nchgbds, /**< pointer to store the number of bound changes */
4002  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
4003  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4004  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4005  SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
4006  )
4007 {
4008  SCIP_VAR* var;
4009  int ntimepoints;
4010  int duration;
4011  int demand;
4012  int peak;
4013  int newlb;
4014  int est;
4015  int lst;
4016  int pos;
4017 
4018  var = vars[idx];
4019  assert(var != NULL);
4020 
4021  duration = durations[idx];
4022  assert(duration > 0);
4023 
4024  demand = demands[idx];
4025  assert(demand > 0);
4026 
4027  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4028  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4029  ntimepoints = SCIPprofileGetNTimepoints(profile);
4030 
4031  /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
4032  * load which we have at the earliest start time (lower bound)
4033  */
4034  (void) SCIPprofileFindLeft(profile, est, &pos);
4035 
4036  SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
4037 
4038  /* we now trying to move the earliest start time in steps of at most "duration" length */
4039  do
4040  {
4041  INFERINFO inferinfo;
4042  SCIP_Bool tightened;
4043  int ect;
4044 
4045 #ifndef NDEBUG
4046  {
4047  /* in debug mode we check that we adjust the search position correctly */
4048  int tmppos;
4049 
4050  (void)SCIPprofileFindLeft(profile, est, &tmppos);
4051  assert(pos == tmppos);
4052  }
4053 #endif
4054  ect = est + duration;
4055  peak = -1;
4056 
4057  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4058  * want a peak which is closest to the earliest completion time
4059  */
4060  do
4061  {
4062  /* check if the profile load conflicts with the demand of the start time variable */
4063  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4064  peak = pos;
4065 
4066  pos++;
4067  }
4068  while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4069 
4070  /* if we found no peak that means current the job could be scheduled at its earliest start time without
4071  * conflicting to the core resource profile
4072  */
4073  if( peak == -1 )
4074  break;
4075 
4076  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4077  * profile. That means we have to move it to the next time point in the resource profile but at most to the
4078  * earliest completion time (the remaining move will done in the next loop)
4079  */
4080  newlb = SCIPprofileGetTime(profile, peak+1);
4081  newlb = MIN(newlb, ect);
4082 
4083  /* if the earliest start time is greater than the lst we detected an infeasibilty */
4084  if( newlb > lst )
4085  {
4086  SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4087 
4088  /* use conflict analysis to analysis the core insertion which was infeasible */
4089  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4090  var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4091 
4092  if( explanation != NULL )
4093  explanation[idx] = TRUE;
4094 
4095  *infeasible = TRUE;
4096 
4097  break;
4098  }
4099 
4100  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4101  * bound change
4102  */
4103  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4104 
4105  /* perform the bound lower bound change */
4106  SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4107  assert(tightened);
4108  assert(!(*infeasible));
4109 
4110  SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4111  (*nchgbds)++;
4112 
4113  /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4115 
4116  /* adjust the earliest start time
4117  *
4118  * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4119  * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4120  * involved.
4121  */
4122  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4123  assert(est >= newlb);
4124 
4125  /* adjust the search position for the resource profile for the next step */
4126  if( est == SCIPprofileGetTime(profile, peak+1) )
4127  pos = peak + 1;
4128  else
4129  pos = peak;
4130  }
4131  while( est < lst );
4132 
4133  return SCIP_OKAY;
4134 }
4135 
4136 /** We are using the core resource profile which contains all core except the one of the start time variable which we
4137  * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4138  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4139  * analysis
4140  */
4141 static
4143  SCIP* scip, /**< SCIP data structure */
4144  SCIP_VAR* var, /**< start time variable to propagate */
4145  int duration, /**< duration of the job */
4146  int demand, /**< demand of the job */
4147  int capacity, /**< cumulative capacity */
4148  SCIP_CONS* cons, /**< constraint which is propagated */
4149  SCIP_PROFILE* profile, /**< resource profile */
4150  int idx, /**< position of the variable to propagate */
4151  int* nchgbds /**< pointer to store the number of bound changes */
4152  )
4153 {
4154  int ntimepoints;
4155  int newub;
4156  int peak;
4157  int pos;
4158  int est;
4159  int lst;
4160  int lct;
4161 
4162  assert(var != NULL);
4163  assert(duration > 0);
4164  assert(demand > 0);
4165 
4166  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4167  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4168 
4169  /* in case the start time variable is fixed do nothing */
4170  if( est == lst )
4171  return SCIP_OKAY;
4172 
4173  ntimepoints = SCIPprofileGetNTimepoints(profile);
4174 
4175  lct = lst + duration;
4176 
4177  /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4178  * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4179  * position gives us the load which we have at the latest completion time minus one
4180  */
4181  (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4182 
4183  SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4184  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
4185 
4186  if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4187  return SCIP_OKAY;
4188 
4189  /* we now trying to move the latest start time in steps of at most "duration" length */
4190  do
4191  {
4192  INFERINFO inferinfo;
4193  SCIP_Bool tightened;
4194  SCIP_Bool infeasible;
4195 
4196  peak = -1;
4197 
4198 #ifndef NDEBUG
4199  {
4200  /* in debug mode we check that we adjust the search position correctly */
4201  int tmppos;
4202 
4203  (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4204  assert(pos == tmppos);
4205  }
4206 #endif
4207 
4208  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4209  * want a peak which is closest to the latest start time
4210  */
4211  do
4212  {
4213  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4214  peak = pos;
4215 
4216  pos--;
4217  }
4218  while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4219 
4220  /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4221  * to the core resource profile
4222  */
4223  if( peak == -1 )
4224  break;
4225 
4226  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4227  * profile. That means the job has be done until that point. Hence that gives us the latest completion
4228  * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4229  * doing in the next loop)
4230  */
4231  newub = SCIPprofileGetTime(profile, peak);
4232  newub = MAX(newub, lst) - duration;
4233  assert(newub >= est);
4234 
4235  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4236  * bound change
4237  */
4238  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4239 
4240  /* perform the bound upper bound change */
4241  SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4242  assert(tightened);
4243  assert(!infeasible);
4244 
4245  SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4246  (*nchgbds)++;
4247 
4248  /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4250 
4251  /* adjust the latest start and completion time
4252  *
4253  * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4254  * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4255  * involved.
4256  */
4257  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4258  assert(lst <= newub);
4259  lct = lst + duration;
4260 
4261  /* adjust the search position for the resource profile for the next step */
4262  if( SCIPprofileGetTime(profile, peak) == lct )
4263  pos = peak - 1;
4264  else
4265  pos = peak;
4266  }
4267  while( est < lst );
4268 
4269  return SCIP_OKAY;
4270 }
4271 
4272 /** compute for the different earliest start and latest completion time the core energy of the corresponding time
4273  * points
4274  */
4275 static
4277  SCIP* scip, /**< SCIP data structure */
4278  SCIP_PROFILE* profile, /**< core profile */
4279  int nvars, /**< number of start time variables (activities) */
4280  int* ests, /**< array of sorted earliest start times */
4281  int* lcts, /**< array of sorted latest completion times */
4282  int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4283  int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4284  )
4285 {
4286  int ntimepoints;
4287  int energy;
4288  int t;
4289  int v;
4290 
4291  ntimepoints = SCIPprofileGetNTimepoints(profile);
4292  t = ntimepoints - 1;
4293  energy = 0;
4294 
4295  /* compute core energy after the earliest start time of each job */
4296  for( v = nvars-1; v >= 0; --v )
4297  {
4298  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4299  {
4300  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4301  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4302  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4303  t--;
4304  }
4305  assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4306 
4307  /* maybe ests[j] is in-between two timepoints */
4308  if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4309  {
4310  assert(t > 0);
4311  coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4312  }
4313  else
4314  coreEnergyAfterEst[v] = energy;
4315  }
4316 
4317  t = ntimepoints - 1;
4318  energy = 0;
4319 
4320  /* compute core energy after the latest completion time of each job */
4321  for( v = nvars-1; v >= 0; --v )
4322  {
4323  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4324  {
4325  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4326  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4327  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4328  t--;
4329  }
4330  assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4331 
4332  /* maybe lcts[j] is in-between two timepoints */
4333  if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4334  {
4335  assert(t > 0);
4336  coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4337  }
4338  else
4339  coreEnergyAfterLct[v] = energy;
4340  }
4341 
4342  return SCIP_OKAY;
4343 }
4344 
4345 /** collect earliest start times, latest completion time, and free energy contributions */
4346 static
4347 void collectDataTTEF(
4348  SCIP* scip, /**< SCIP data structure */
4349  int nvars, /**< number of start time variables (activities) */
4350  SCIP_VAR** vars, /**< array of start time variables */
4351  int* durations, /**< array of durations */
4352  int* demands, /**< array of demands */
4353  int hmin, /**< left bound of time axis to be considered (including hmin) */
4354  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4355  int* permests, /**< array to store the variable positions */
4356  int* ests, /**< array to store earliest start times */
4357  int* permlcts, /**< array to store the variable positions */
4358  int* lcts, /**< array to store latest completion times */
4359  int* ects, /**< array to store earliest completion times of the flexible part of the job */
4360  int* lsts, /**< array to store latest start times of the flexible part of the job */
4361  int* flexenergies /**< array to store the flexible energies of each job */
4362  )
4363 {
4364  int v;
4365 
4366  for( v = 0; v < nvars; ++ v)
4367  {
4368  int duration;
4369  int leftadjust;
4370  int rightadjust;
4371  int core;
4372  int est;
4373  int lct;
4374  int ect;
4375  int lst;
4376 
4377  duration = durations[v];
4378  assert(duration > 0);
4379 
4380  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4381  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
4382  ect = est + duration;
4383  lct = lst + duration;
4384 
4385  ests[v] = est;
4386  lcts[v] = lct;
4387  permests[v] = v;
4388  permlcts[v] = v;
4389 
4390  /* compute core time window which lies within the effective horizon */
4391  core = computeCoreWithInterval(hmin, hmax, ect, lst);
4392 
4393  /* compute the number of time steps the job could run before the effective horizon */
4394  leftadjust = MAX(0, hmin - est);
4395 
4396  /* compute the number of time steps the job could run after the effective horizon */
4397  rightadjust = MAX(0, lct - hmax);
4398 
4399  /* compute for each job the energy which is flexible; meaning not part of the core */
4400  flexenergies[v] = duration - leftadjust - rightadjust - core;
4401  flexenergies[v] = MAX(0, flexenergies[v]);
4402  flexenergies[v] *= demands[v];
4403  assert(flexenergies[v] >= 0);
4404 
4405  /* the earliest completion time of the flexible energy */
4406  ects[v] = MIN(ect, lst);
4407 
4408  /* the latest start time of the flexible energy */
4409  lsts[v] = MAX(ect, lst);
4410  }
4411 }
4412 
4413 /** try to tighten the lower bound of the given variable */
4414 static
4416  SCIP* scip, /**< SCIP data structure */
4417  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4418  int nvars, /**< number of start time variables (activities) */
4419  SCIP_VAR** vars, /**< array of start time variables */
4420  int* durations, /**< array of durations */
4421  int* demands, /**< array of demands */
4422  int capacity, /**< cumulative capacity */
4423  int hmin, /**< left bound of time axis to be considered (including hmin) */
4424  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4425  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4426  int duration, /**< duration of the job */
4427  int demand, /**< demand of the job */
4428  int est, /**< earliest start time of the job */
4429  int ect, /**< earliest completion time of the flexible part of the job */
4430  int lct, /**< latest completion time of the job */
4431  int begin, /**< begin of the time window under investigation */
4432  int end, /**< end of the time window under investigation */
4433  int energy, /**< available energy for the flexible part of the hob within the time window */
4434  int* bestlb, /**< pointer to strope the best lower bound change */
4435  int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4436  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4437  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4438  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4439  )
4440 {
4441  int newlb;
4442 
4443  assert(begin >= hmin);
4444  assert(end <= hmax);
4445 
4446  /* check if the time-table edge-finding should infer bounds */
4447  if( !conshdlrdata->ttefinfer )
4448  return SCIP_OKAY;
4449 
4450  /* if the job can be processed completely before or after the time window, nothing can be tightened */
4451  if( est >= end || ect <= begin )
4452  return SCIP_OKAY;
4453 
4454  /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4455  * skip since the overload check will do the job
4456  */
4457  if( est >= begin && ect <= end )
4458  return SCIP_OKAY;
4459 
4460  /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4461  * earliest start time
4462  */
4463  if( energy >= demand * (MAX(begin, est) - MIN(end, ect)) )
4464  return SCIP_OKAY;
4465 
4466  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4467  * present; therefore, we need to add the core;
4468  *
4469  * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4470  * compute the earliest completion time of the (whole) job
4471  */
4472  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4473 
4474  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4475  *
4476  * @note we can round down the compute duration w.r.t. the available energy
4477  */
4478  newlb = end - energy / demand;
4479 
4480  /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4481  * bound (latest start time); meaning it is not possible to schedule the job
4482  */
4483  if( newlb > lct - duration )
4484  {
4485  /* initialize conflict analysis if conflict analysis is applicable */
4487  {
4488  SCIP_Real relaxedbd;
4489 
4490  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4491 
4492  /* it is enough to overshoot the upper bound of the variable by one */
4493  relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4494 
4495  /* initialize conflict analysis */
4497 
4498  /* added to upper bound (which was overcut be new lower bound) of the variable */
4499  SCIP_CALL( SCIPaddConflictUb(scip, var, NULL) );
4500 
4501  /* analyze the infeasible */
4502  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4503  begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4504 
4505  (*initialized) = TRUE;
4506  }
4507 
4508  (*cutoff) = TRUE;
4509  }
4510  else if( newlb > (*bestlb) )
4511  {
4512  INFERINFO inferinfo;
4513 
4514  assert(newlb > begin);
4515 
4516  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4517 
4518  /* construct inference information */
4519  (*inferinfos) = inferInfoToInt(inferinfo);
4520  (*bestlb) = newlb;
4521  }
4522 
4523  return SCIP_OKAY;
4524 }
4525 
4526 /** try to tighten the upper bound of the given variable */
4527 static
4529  SCIP* scip, /**< SCIP data structure */
4530  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4531  int nvars, /**< number of start time variables (activities) */
4532  SCIP_VAR** vars, /**< array of start time variables */
4533  int* durations, /**< array of durations */
4534  int* demands, /**< array of demands */
4535  int capacity, /**< cumulative capacity */
4536  int hmin, /**< left bound of time axis to be considered (including hmin) */
4537  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4538  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4539  int duration, /**< duration of the job */
4540  int demand, /**< demand of the job */
4541  int est, /**< earliest start time of the job */
4542  int lst, /**< latest start time of the flexible part of the job */
4543  int lct, /**< latest completion time of the job */
4544  int begin, /**< begin of the time window under investigation */
4545  int end, /**< end of the time window under investigation */
4546  int energy, /**< available energy for the flexible part of the hob within the time window */
4547  int* bestub, /**< pointer to strope the best upper bound change */
4548  int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4549  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4550  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4551  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4552  )
4553 {
4554  int newub;
4555 
4556  assert(begin >= hmin);
4557  assert(end <= hmax);
4558  assert(est < begin);
4559 
4560  /* check if the time-table edge-finding should infer bounds */
4561  if( !conshdlrdata->ttefinfer )
4562  return SCIP_OKAY;
4563 
4564  /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4565  if( lst >= end || lct <= begin )
4566  return SCIP_OKAY;
4567 
4568  /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4569  * skip since the overload check will do the job
4570  */
4571  if( lst >= begin && lct <= end )
4572  return SCIP_OKAY;
4573 
4574  /* check if the available energy in the time window is to small to handle the flexible part of the job */
4575  if( energy >= demand * (MIN(end, lct) - MAX(begin, lst)) )
4576  return SCIP_OKAY;
4577 
4578  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4579  * present; therefore, we need to add the core;
4580  *
4581  * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4582  * latest start of the (whole) job
4583  */
4584  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4585  assert(energy >= 0);
4586 
4587  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4588  *
4589  * @note we can round down the compute duration w.r.t. the available energy
4590  */
4591  assert(demand > 0);
4592  newub = begin - duration + energy / demand;
4593 
4594  /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4595  * bound (earliest start time); meaning it is not possible to schedule the job
4596  */
4597  if( newub < est )
4598  {
4599  /* initialize conflict analysis if conflict analysis is applicable */
4601  {
4602  SCIP_Real relaxedbd;
4603 
4604  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4605 
4606  /* it is enough to undershoot the lower bound of the variable by one */
4607  relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4608 
4609  /* initialize conflict analysis */
4611 
4612  /* added to lower bound (which was undercut be new upper bound) of the variable */
4613  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
4614 
4615  /* analyze the infeasible */
4616  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4617  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4618 
4619  (*initialized) = TRUE;
4620  }
4621 
4622  (*cutoff) = TRUE;
4623  }
4624  else if( newub < (*bestub) )
4625  {
4626  INFERINFO inferinfo;
4627 
4628  assert(newub < begin);
4629 
4630  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4631 
4632  /* construct inference information */
4633  (*inferinfos) = inferInfoToInt(inferinfo);
4634  (*bestub) = newub;
4635  }
4636 
4637  return SCIP_OKAY;
4638 }
4639 
4640 /** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4641 static
4643  SCIP* scip, /**< SCIP data structure */
4644  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4645  int nvars, /**< number of start time variables (activities) */
4646  SCIP_VAR** vars, /**< array of start time variables */
4647  int* durations, /**< array of durations */
4648  int* demands, /**< array of demands */
4649  int capacity, /**< cumulative capacity */
4650  int hmin, /**< left bound of time axis to be considered (including hmin) */
4651  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4652  int* newlbs, /**< array to buffer new lower bounds */
4653  int* newubs, /**< array to buffer new upper bounds */
4654  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4655  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4656  int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4657  int* flexenergies, /**< array of flexible energies in the same order as the variables */
4658  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4659  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4660  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4661  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4662  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4663  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4664  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4665  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4666  )
4667 {
4668  int coreEnergyAfterEnd;
4669  int maxavailable;
4670  int minavailable;
4671  int totalenergy;
4672  int nests;
4673  int est;
4674  int lct;
4675  int start;
4676  int end;
4677  int v;
4678 
4679  est = INT_MAX;
4680  lct = INT_MIN;
4681 
4682  /* compute earliest start and latest completion time of all jobs */
4683  for( v = 0; v < nvars; ++v )
4684  {
4685  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4686  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4687 
4688  est = MIN(est, start);
4689  lct = MAX(lct, end);
4690  }
4691 
4692  /* adjust the effective time horizon */
4693  hmin = MAX(hmin, est);
4694  hmax = MIN(hmax, lct);
4695 
4696  end = hmax + 1;
4697  coreEnergyAfterEnd = -1;
4698 
4699  maxavailable = (hmax - hmin) * capacity;
4700  minavailable = maxavailable;
4701  totalenergy = computeTotalEnergy(durations, demands, nvars);
4702 
4703  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4704  if( (lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4705  return SCIP_OKAY;
4706 
4707  nests = nvars;
4708 
4709  /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4710  * times define the end of the time interval under investigation
4711  */
4712  for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4713  {
4714  int flexenergy;
4715  int minbegin;
4716  int lbenergy;
4717  int lbcand;
4718  int i;
4719 
4720  lct = lcts[v];
4721 
4722  /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4723  * infinity capacity is available; hence we skip that
4724  */
4725  if( lct > hmax )
4726  continue;
4727 
4728  /* if the latest completion time is smaller then hmin we have to stop */
4729  if( lct <= hmin )
4730  {
4731  assert(v == 0 || lcts[v-1] <= lcts[v]);
4732  break;
4733  }
4734 
4735  /* if the latest completion time equals to previous end time, we can continue since this particular interval
4736  * induced by end was just analyzed
4737  */
4738  if( lct == end )
4739  continue;
4740 
4741  assert(lct < end);
4742 
4743  /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4744  * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4745  * free energy; if so it means that in the next iterate the free-energy cannot be negative
4746  */
4747  if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4748  {
4749  int freeenergy;
4750 
4751  assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4752  assert(coreEnergyAfterEnd >= 0);
4753 
4754  /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4755  freeenergy = capacity * (end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4756 
4757  if( freeenergy <= minavailable )
4758  {
4759  SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%d>, free energy <%d>)\n", lct, minavailable, freeenergy);
4760  continue;
4761  }
4762  }
4763 
4764  SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4765 
4766  end = lct;
4767  coreEnergyAfterEnd = coreEnergyAfterLct[v];
4768 
4769  flexenergy = 0;
4770  minavailable = maxavailable;
4771  minbegin = hmax;
4772  lbcand = -1;
4773  lbenergy = 0;
4774 
4775  /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4776  * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4777  * wider
4778  */
4779  for( i = nests-1; i >= 0; --i )
4780  {
4781  SCIP_VAR* var;
4782  int freeenergy;
4783  int duration;
4784  int demand;
4785  int begin;
4786  int idx;
4787  int lst;
4788 
4789  idx = perm[i];
4790  assert(idx >= 0);
4791  assert(idx < nvars);
4792  assert(!(*cutoff));
4793 
4794  /* the earliest start time of the job */
4795  est = ests[i];
4796 
4797  /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4798  * latest completion times (which define end) are scant in non-increasing order
4799  */
4800  if( end <= est )
4801  {
4802  nests--;
4803  continue;
4804  }
4805 
4806  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4807  * current ending time
4808  */
4809  if( (end - est) * capacity >= totalenergy )
4810  break;
4811 
4812  var = vars[idx];
4813  assert(var != NULL);
4814 
4815  duration = durations[idx];
4816  assert(duration > 0);
4817 
4818  demand = demands[idx];
4819  assert(demand > 0);
4820 
4821  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4822 
4823  /* the latest start time of the free part of the job */
4824  lst = lsts[idx];
4825 
4826  /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4827  * investigation; hence the overload check will do the the job
4828  */
4829  assert(est <= minbegin);
4830  if( minavailable < maxavailable && est < minbegin )
4831  {
4832  assert(!(*cutoff));
4833 
4834  /* try to tighten the upper bound */
4835  SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4836  var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4837  initialized, explanation, cutoff) );
4838 
4839  if( *cutoff )
4840  break;
4841  }
4842 
4843  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4844  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4845 
4846  begin = est;
4847  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4848 
4849  /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4850  * free energy
4851  */
4852  if( begin < hmin )
4853  break;
4854 
4855  /* compute the contribution to the flexible energy */
4856  if( lct <= end )
4857  {
4858  /* if the jobs has to finish before the end, all the energy has to be scheduled */
4859  assert(lst >= begin);
4860  assert(flexenergies[idx] >= 0);
4861  flexenergy += flexenergies[idx];
4862  }
4863  else
4864  {
4865  /* the job partly overlaps with the end */
4866  int candenergy;
4867  int energy;
4868 
4869  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4870  * w.r.t. latest start time
4871  *
4872  * @note we need to be aware of the effective horizon
4873  */
4874  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4875  assert(end - lst < duration);
4876  assert(energy >= 0);
4877 
4878  /* adjust the flexible energy of the time interval */
4879  flexenergy += energy;
4880 
4881  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4882  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4883  assert(candenergy >= 0);
4884 
4885  /* check if we found a better candidate */
4886  if( candenergy > lbenergy )
4887  {
4888  lbenergy = candenergy;
4889  lbcand = idx;
4890  }
4891  }
4892 
4893  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4894  assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4895 
4896  /* compute the energy which is not used yet */
4897  freeenergy = capacity * (end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4898 
4899  /* check overload */
4900  if( freeenergy < 0 )
4901  {
4902  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4903 
4904  /* initialize conflict analysis if conflict analysis is applicable */
4906  {
4907  /* analyze infeasibilty */
4909 
4910  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4911  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
4912  conshdlrdata->usebdwidening, explanation) );
4913 
4914  (*initialized) = TRUE;
4915  }
4916 
4917  (*cutoff) = TRUE;
4918 
4919  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4920  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
4921 
4922  break;
4923  }
4924 
4925  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4926  if( lbenergy > 0 && freeenergy < lbenergy )
4927  {
4928  int energy;
4929  int newlb;
4930  int ect;
4931 
4932  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4933  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4934 
4935  /* remove the energy of our job from the ... */
4936  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, end - lsts[lbcand])) * demands[lbcand];
4937 
4938  newlb = end - (int)(energy / demands[lbcand]);
4939 
4940  if( newlb > lst )
4941  {
4942  /* initialize conflict analysis if conflict analysis is applicable */
4944  {
4945  SCIP_Real relaxedbd;
4946 
4947  /* analyze infeasibilty */
4949 
4950  relaxedbd = lst + 1.0;
4951 
4952  /* added to upper bound (which was overcut be new lower bound) of the variable */
4953  SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4954 
4955  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4956  begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
4957  conshdlrdata->usebdwidening, explanation) );
4958 
4959  (*initialized) = TRUE;
4960  }
4961 
4962  (*cutoff) = TRUE;
4963  break;
4964  }
4965  else if( newlb > newlbs[lbcand] )
4966  {
4967  INFERINFO inferinfo;
4968 
4969  /* construct inference information */
4970  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4971 
4972  /* buffer upper bound change */
4973  lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
4974  newlbs[lbcand] = newlb;
4975  }
4976  }
4977 
4978  /* check if the current interval has a smaller free energy */
4979  if( minavailable > freeenergy )
4980  {
4981  minavailable = freeenergy;
4982  minbegin = begin;
4983  }
4984  assert(minavailable >= 0);
4985  }
4986  }
4987 
4988  return SCIP_OKAY;
4989 }
4990 
4991 /** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
4992 static
4994  SCIP* scip, /**< SCIP data structure */
4995  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4996  int nvars, /**< number of start time variables (activities) */
4997  SCIP_VAR** vars, /**< array of start time variables */
4998  int* durations, /**< array of durations */
4999  int* demands, /**< array of demands */
5000  int capacity, /**< cumulative capacity */
5001  int hmin, /**< left bound of time axis to be considered (including hmin) */
5002  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5003  int* newlbs, /**< array to buffer new lower bounds */
5004  int* newubs, /**< array to buffer new upper bounds */
5005  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
5006  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
5007  int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
5008  int* flexenergies, /**< array of flexible energies in the same order as the variables */
5009  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
5010  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
5011  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
5012  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
5013  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
5014  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5015  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5016  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5017  )
5018 {
5019  int coreEnergyAfterStart;
5020  int maxavailable;
5021  int minavailable;
5022  int totalenergy;
5023  int nlcts;
5024  int begin;
5025  int minest;
5026  int maxlct;
5027  int start;
5028  int end;
5029  int v;
5030 
5031  if( *cutoff )
5032  return SCIP_OKAY;
5033 
5034  begin = hmin - 1;
5035 
5036  minest = INT_MAX;
5037  maxlct = INT_MIN;
5038 
5039  /* compute earliest start and latest completion time of all jobs */
5040  for( v = 0; v < nvars; ++v )
5041  {
5042  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5043  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
5044 
5045  minest = MIN(minest, start);
5046  maxlct = MAX(maxlct, end);
5047  }
5048 
5049  /* adjust the effective time horizon */
5050  hmin = MAX(hmin, minest);
5051  hmax = MIN(hmax, maxlct);
5052 
5053  maxavailable = (hmax - hmin) * capacity;
5054  totalenergy = computeTotalEnergy(durations, demands, nvars);
5055 
5056  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5057  if( (lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5058  return SCIP_OKAY;
5059 
5060  nlcts = 0;
5061 
5062  /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5063  * define the start of the time interval under investigation
5064  */
5065  for( v = 0; v < nvars; ++v )
5066  {
5067  int flexenergy;
5068  int minend;
5069  int ubenergy;
5070  int ubcand;
5071  int est;
5072  int i;
5073 
5074  est = ests[v];
5075 
5076  /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5077  * infinity capacity is available; hence we skip that
5078  */
5079  if( est < hmin )
5080  continue;
5081 
5082  /* if the earliest start time is larger or equal then hmax we have to stop */
5083  if( est >= hmax )
5084  break;
5085 
5086  /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5087  * induced by start was just analyzed
5088  */
5089  if( est == begin )
5090  continue;
5091 
5092  assert(est > begin);
5093 
5094  SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5095 
5096  begin = est;
5097  coreEnergyAfterStart = coreEnergyAfterEst[v];
5098 
5099  flexenergy = 0;
5100  minavailable = maxavailable;
5101  minend = hmin;
5102  ubcand = -1;
5103  ubenergy = 0;
5104 
5105  /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5106  * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5107  */
5108  for( i = nlcts; i < nvars; ++i )
5109  {
5110  SCIP_VAR* var;
5111  int freeenergy;
5112  int duration;
5113  int demand;
5114  int idx;
5115  int lct;
5116  int ect;
5117 
5118  idx = perm[i];
5119  assert(idx >= 0);
5120  assert(idx < nvars);
5121  assert(!(*cutoff));
5122 
5123  /* the earliest start time of the job */
5124  lct = lcts[i];
5125 
5126  /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5127  * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5128  */
5129  if( lct <= begin )
5130  {
5131  nlcts++;
5132  continue;
5133  }
5134 
5135  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5136  * start with current beginning time
5137  */
5138  if( (lct - begin) * capacity >= totalenergy )
5139  break;
5140 
5141  var = vars[idx];
5142  assert(var != NULL);
5143 
5144  duration = durations[idx];
5145  assert(duration > 0);
5146 
5147  demand = demands[idx];
5148  assert(demand > 0);
5149 
5150  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5151 
5152  /* the earliest completion time of the flexible part of the job */
5153  ect = ects[idx];
5154 
5155  /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5156  * investigation; hence the overload check will do the the job
5157  */
5158  assert(lct >= minend);
5159  if( minavailable < maxavailable && lct > minend )
5160  {
5161  assert(!(*cutoff));
5162 
5163  /* try to tighten the upper bound */
5164  SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5165  var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5166  initialized, explanation, cutoff) );
5167 
5168  if( *cutoff )
5169  return SCIP_OKAY;
5170  }
5171 
5172  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5173  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5174 
5175  end = lct;
5176  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5177 
5178  /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5179  * free energy
5180  */
5181  if( end > hmax )
5182  break;
5183 
5184  /* compute the contribution to the flexible energy */
5185  if( est >= begin )
5186  {
5187  /* if the jobs has to finish before the end, all the energy has to be scheduled */
5188  assert(ect <= end);
5189  assert(flexenergies[idx] >= 0);
5190  flexenergy += flexenergies[idx];
5191  }
5192  else
5193  {
5194  /* the job partly overlaps with the end */
5195  int candenergy;
5196  int energy;
5197 
5198  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5199  * w.r.t. latest start time
5200  *
5201  * @note we need to be aware of the effective horizon
5202  */
5203  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5204  assert(ect - begin < duration);
5205  assert(energy >= 0);
5206 
5207  /* adjust the flexible energy of the time interval */
5208  flexenergy += energy;
5209 
5210  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5211  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5212  assert(candenergy >= 0);
5213 
5214  /* check if we found a better candidate */
5215  if( candenergy > ubenergy )
5216  {
5217  ubenergy = candenergy;
5218  ubcand = idx;
5219  }
5220  }
5221 
5222  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5223  assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5224 
5225  /* compute the energy which is not used yet */
5226  freeenergy = capacity * (end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5227 
5228  /* check overload */
5229  if( freeenergy < 0 )
5230  {
5231  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5232 
5233  /* initialize conflict analysis if conflict analysis is applicable */
5235  {
5236  /* analyze infeasibilty */
5238 
5239  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5240  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
5241  conshdlrdata->usebdwidening, explanation) );
5242 
5243  (*initialized) = TRUE;
5244  }
5245 
5246  (*cutoff) = TRUE;
5247 
5248  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5249  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5250 
5251  return SCIP_OKAY;
5252  }
5253 
5254  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5255  if( ubenergy > 0 && freeenergy < ubenergy )
5256  {
5257  int energy;
5258  int newub;
5259  int lst;
5260 
5261  duration = durations[ubcand];
5262  assert(duration > 0);
5263 
5264  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5265  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5266 
5267  /* remove the energy of our job from the ... */
5268  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, ects[ubcand] - begin)) * demands[ubcand];
5269 
5270  newub = begin - duration + (int)(energy / demands[ubcand]);
5271 
5272  if( newub < ect - duration )
5273  {
5274  /* initialize conflict analysis if conflict analysis is applicable */
5276  {
5277  SCIP_Real relaxedbd;
5278  /* analyze infeasibilty */
5280 
5281  relaxedbd = ect - duration - 1.0;
5282 
5283  /* added to lower bound (which was undercut be new upper bound) of the variable */
5284  SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5285 
5286  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5287  begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5288  conshdlrdata->usebdwidening, explanation) );
5289 
5290  (*initialized) = TRUE;
5291  }
5292 
5293  (*cutoff) = TRUE;
5294  return SCIP_OKAY;
5295  }
5296  else if( newub < newubs[ubcand] )
5297  {
5298  INFERINFO inferinfo;
5299 
5300  /* construct inference information */
5301  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5302 
5303  /* buffer upper bound change */
5304  ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5305  newubs[ubcand] = newub;
5306  }
5307  }
5308 
5309  /* check if the current interval has a smaller free energy */
5310  if( minavailable > freeenergy )
5311  {
5312  minavailable = freeenergy;
5313  minend = end;
5314  }
5315  assert(minavailable >= 0);
5316  }
5317  }
5318 
5319  return SCIP_OKAY;
5320 }
5321 
5322 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5323  * edge-finding
5324  *
5325  * @note The algorithm is based on the following two papers:
5326  * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5327  * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5328  * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5329  * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5330  * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5331  */
5332 static
5334  SCIP* scip, /**< SCIP data structure */
5335  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5336  SCIP_PROFILE* profile, /**< current core profile */
5337  int nvars, /**< number of start time variables (activities) */
5338  SCIP_VAR** vars, /**< array of start time variables */
5339  int* durations, /**< array of durations */
5340  int* demands, /**< array of demands */
5341  int capacity, /**< cumulative capacity */
5342  int hmin, /**< left bound of time axis to be considered (including hmin) */
5343  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5344  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5345  int* nchgbds, /**< pointer to store the number of bound changes */
5346  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5347  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5348  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5349  )
5350 {
5351  int* coreEnergyAfterEst;
5352  int* coreEnergyAfterLct;
5353  int* flexenergies;
5354  int* permests;
5355  int* permlcts;
5356  int* lcts;
5357  int* ests;
5358  int* ects;
5359  int* lsts;
5360 
5361  int* newlbs;
5362  int* newubs;
5363  int* lbinferinfos;
5364  int* ubinferinfos;
5365 
5366  int v;
5367 
5368  /* check if a cutoff was already detected */
5369  if( (*cutoff) )
5370  return SCIP_OKAY;
5371 
5372  /* check if at least the basic overload checking should be perfomed */
5373  if( !conshdlrdata->ttefcheck )
5374  return SCIP_OKAY;
5375 
5376  SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5377 
5378  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5379  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5380  SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5381  SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5382  SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5383  SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5384  SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5385  SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5386  SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5387 
5388  SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5389  SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5390  SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5391  SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5392 
5393  /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5394  for( v = 0; v < nvars; ++v )
5395  {
5396  newlbs[v] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5397  newubs[v] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5398  lbinferinfos[v] = 0;
5399  ubinferinfos[v] = 0;
5400  }
5401 
5402  /* collect earliest start times, latest completion time, and free energy contributions */
5403  collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5404 
5405  /* sort the earliest start times and latest completion in non-decreasing order */
5406  SCIPsortIntInt(ests, permests, nvars);
5407  SCIPsortIntInt(lcts, permlcts, nvars);
5408 
5409  /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5410  * points
5411  */
5412  SCIP_CALL( computeCoreEngeryAfter(scip, profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct) );
5413 
5414  /* propagate the upper bounds and "opportunistically" the lower bounds */
5415  SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5416  newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5417  permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5418 
5419  /* propagate the lower bounds and "opportunistically" the upper bounds */
5420  SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5421  newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5422  permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5423 
5424  /* apply the buffer bound changes */
5425  for( v = 0; v < nvars && !(*cutoff); ++v )
5426  {
5427  SCIP_Bool infeasible;
5428  SCIP_Bool tightened;
5429 
5430  SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v], TRUE, &infeasible, &tightened) );
5431 
5432  /* since we change first the lower bound of the variable an infeasibilty should be detected */
5433  assert(!infeasible);
5434 
5435  if( tightened )
5436  {
5437  (*nchgbds)++;
5438 
5439  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5441  }
5442 
5443 
5444  SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v], TRUE, &infeasible, &tightened) );
5445 
5446  /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5447  * bound update can be infeasible
5448  */
5449  if( infeasible )
5450  {
5452  {
5453  INFERINFO inferinfo;
5454  SCIP_VAR* var;
5455  int begin;
5456  int end;
5457 
5458  var = vars[v];
5459  assert(var != NULL);
5460 
5461  /* initialize conflict analysis */
5463 
5464  /* convert int to inference information */
5465  inferinfo = intToInferInfo(ubinferinfos[v]);
5466 
5467  /* collect time window from inference information */
5468  begin = inferInfoGetData1(inferinfo);
5469  end = inferInfoGetData2(inferinfo);
5470  assert(begin < end);
5471 
5472  /* added to lower bound (which was undercut be new upper bound) of the variable */
5473  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
5474 
5475  /* analysis the upper bound change */
5476  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5477  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5478  conshdlrdata->usebdwidening, explanation) );
5479 
5480  (*initialized) = TRUE;
5481  }
5482 
5483  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5484  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5485 
5486  (*cutoff) = TRUE;
5487  break;
5488  }
5489 
5490  if( tightened )
5491  {
5492  (*nchgbds)++;
5493 
5494  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5496  }
5497  }
5498 
5499  SCIPfreeBufferArray(scip, &ubinferinfos);
5500  SCIPfreeBufferArray(scip, &lbinferinfos);
5501  SCIPfreeBufferArray(scip, &newubs);
5502  SCIPfreeBufferArray(scip, &newlbs);
5503 
5504  /* free buffer arrays */
5505  SCIPfreeBufferArray(scip, &lsts);
5506  SCIPfreeBufferArray(scip, &ects);
5507  SCIPfreeBufferArray(scip, &ests);
5508  SCIPfreeBufferArray(scip, &lcts);
5509  SCIPfreeBufferArray(scip, &permests);
5510  SCIPfreeBufferArray(scip, &permlcts);
5511  SCIPfreeBufferArray(scip, &flexenergies);
5512  SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5513  SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5514 
5515  return SCIP_OKAY;
5516 }
5517 
5518 /** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5519  * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5520  * time table propagator
5521  */
5522 static
5524  SCIP* scip, /**< SCIP data structure */
5525  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5526  SCIP_PROFILE* profile, /**< core profile */
5527  int nvars, /**< number of start time variables (activities) */
5528  SCIP_VAR** vars, /**< array of start time variables */
5529  int* durations, /**< array of durations */
5530  int* demands, /**< array of demands */
5531  int capacity, /**< cumulative capacity */
5532  int hmin, /**< left bound of time axis to be considered (including hmin) */
5533  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5534  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5535  int* nchgbds, /**< pointer to store the number of bound changes */
5536  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5537  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5538  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5539  )
5540 {
5541  SCIP_Bool infeasible;
5542  int v;
5543 
5544  assert(scip != NULL);
5545  assert(nvars > 0);
5546  assert(cons != NULL);
5547  assert(cutoff != NULL);
5548 
5549  /* check if already a cutoff was detected */
5550  if( (*cutoff) )
5551  return SCIP_OKAY;
5552 
5553  /* check if the time tabling should infer bounds */
5554  if( !conshdlrdata->ttinfer )
5555  return SCIP_OKAY;
5556 
5557  assert(*initialized == FALSE);
5558 
5559  SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5560  SCIPconsGetName(cons), hmin, hmax, capacity);
5561 
5562  infeasible = FALSE;
5563 
5564  /* if core profile is empty; nothing to do */
5565  if( SCIPprofileGetNTimepoints(profile) <= 1 )
5566  return SCIP_OKAY;
5567 
5568  /* start checking each job whether the bounds can be improved */
5569  for( v = 0; v < nvars; ++v )
5570  {
5571  SCIP_VAR* var;
5572  int demand;
5573  int duration;
5574  int begin;
5575  int end;
5576  int est;
5577  int lst;
5578 
5579  var = vars[v];
5580  assert(var != NULL);
5581 
5582  duration = durations[v];
5583  assert(duration > 0);
5584 
5585  /* collect earliest and latest start time */
5586  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5587  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5588 
5589  /* check if the start time variables is already fixed; in that case we can ignore the job */
5590  if( est == lst )
5591  continue;
5592 
5593  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5594  if( lst + duration <= hmin || est >= hmax )
5595  continue;
5596 
5597  /* compute core interval w.r.t. effective time horizon */
5598  begin = MAX(hmin, lst);
5599  end = MIN(hmax, est + duration);
5600 
5601  demand = demands[v];
5602  assert(demand > 0);
5603 
5604  /* if the job has a core, remove it first */
5605  if( begin < end )
5606  {
5607  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5608  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5609 
5610  SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5611  }
5612 
5613  /* first try to update the earliest start time */
5614  SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5615  profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5616 
5617  if( *cutoff )
5618  break;
5619 
5620  /* second try to update the latest start time */
5621  SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5622  profile, v, nchgbds) );
5623 
5624  if( *cutoff )
5625  break;
5626 
5627  /* collect the potentially updated earliest and latest start time */
5628  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5629  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5630 
5631  /* compute core interval w.r.t. effective time horizon */
5632  begin = MAX(hmin, lst);
5633  end = MIN(hmax, est + duration);
5634 
5635  /* after updating the bound we might have a new core */
5636  if( begin < end )
5637  {
5638  int pos;
5639 
5640  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5641  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5642 
5643  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5644 
5645  if( infeasible )
5646  {
5647  /* use conflict analysis to analysis the core insertion which was infeasible */
5648  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5649  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5650 
5651  if( explanation != NULL )
5652  explanation[v] = TRUE;
5653 
5654  (*cutoff) = TRUE;
5655 
5656  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5657  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
5658 
5659  break;
5660  }
5661  }
5662  }
5663 
5664  return SCIP_OKAY;
5665 }
5666 
5667 
5668 /** node data structure for the binary tree used for edgefinding (with overload checking) */
5669 struct SCIP_NodeData
5670 {
5671  SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5672  SCIP_Real key; /**< key which is to insert the corresponding search node */
5673  int est; /**< earliest start time if the node data belongs to a leaf */
5674  int lct; /**< latest completion time if the node data belongs to a leaf */
5675  int demand; /**< demand of the job if the node data belongs to a leaf */
5676  int duration; /**< duration of the job if the node data belongs to a leaf */
5677  int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5678  int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5679  int enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5680  int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5681  int energylambda;
5682  int enveloplambda;
5683  int idx; /**< index of the start time variable in the (global) variable array */
5684  SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5685 };
5686 typedef struct SCIP_NodeData SCIP_NODEDATA;
5688 /** creates a node data structure */
5689 static
5691  SCIP* scip, /**< SCIP data structure */
5692  SCIP_NODEDATA** nodedata /**< pointer to store the create node data */
5693  )
5694 {
5695  SCIP_CALL( SCIPallocBuffer(scip, nodedata) );
5696  (*nodedata)->var = NULL;
5697  (*nodedata)->key = SCIP_INVALID;
5698  (*nodedata)->est = INT_MIN;
5699  (*nodedata)->lct = INT_MAX;
5700  (*nodedata)->duration = 0;
5701  (*nodedata)->demand = 0;
5702  (*nodedata)->enveloptheta = -1;
5703  (*nodedata)->energytheta = 0;
5704  (*nodedata)->enveloplambda = -1;
5705  (*nodedata)->energylambda = -1;
5706  (*nodedata)->idx = -1;
5707  (*nodedata)->intheta = TRUE;
5708 
5709  return SCIP_OKAY;
5710 }
5711 
5712 /** frees a node data structure */
5713 static
5714 void freeNodedata(
5715  SCIP* scip, /**< SCIP data structure */
5716  SCIP_NODEDATA** nodedata /**< pointer to store node data which should be freed */
5717  )
5718 {
5719  if( *nodedata != NULL )
5720  {
5721  SCIPfreeBuffer(scip, nodedata);
5722  }
5723 }
5724 
5725 /** update node data structure strating form the given node along the path to the root node */
5726 static
5728  SCIP* scip, /**< SCIP data structure */
5729  SCIP_BTNODE* node /**< search node which inserted */
5730  )
5731 {
5732  SCIP_BTNODE* left;
5733  SCIP_BTNODE* right;
5734  SCIP_NODEDATA* nodedata;
5735  SCIP_NODEDATA* leftdata;
5736  SCIP_NODEDATA* rightdata;
5737 
5738  SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5739 
5740  if( SCIPbtnodeIsLeaf(node) )
5741  node = SCIPbtnodeGetParent(node);
5742 
5743  while( node != NULL )
5744  {
5745  /* get node data */
5746  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5747  assert(nodedata != NULL);
5748 
5749  /* collect node data from left node */
5750  left = SCIPbtnodeGetLeftchild(node);
5751  assert(left != NULL);
5752  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5753  assert(leftdata != NULL);
5754 
5755  /* collect node data from right node */
5756  right = SCIPbtnodeGetRightchild(node);
5757  assert(right != NULL);
5758  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5759  assert(rightdata != NULL);
5760 
5761  /* update envelop and energy */
5762  if( leftdata->enveloptheta >= 0 )
5763  {
5764  assert(rightdata->energytheta != -1);
5765  nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5766  }
5767  else
5768  nodedata->enveloptheta = rightdata->enveloptheta;
5769 
5770  assert(leftdata->energytheta != -1);
5771  assert(rightdata->energytheta != -1);
5772  nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5773 
5774  if( leftdata->enveloplambda >= 0 )
5775  {
5776  assert(rightdata->energytheta != -1);
5777  nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5778  }
5779  else
5780  nodedata->enveloplambda = rightdata->enveloplambda;
5781 
5782  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5783  nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5784 
5785  SCIPdebugMsg(scip, "node <%p> lambda envelop %d\n", (void*)node, nodedata->enveloplambda);
5786 
5787  if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5788  {
5789  assert(rightdata->energytheta != -1);
5790  assert(leftdata->energytheta != -1);
5791  nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5792  }
5793  else if( rightdata->energylambda >= 0 )
5794  {
5795  assert(leftdata->energytheta != -1);
5796  nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5797  }
5798  else if( leftdata->energylambda >= 0 )
5799  {
5800  assert(rightdata->energytheta != -1);
5801  nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5802  }
5803  else
5804  nodedata->energylambda = -1;
5805 
5806  /* go to parent */
5807  node = SCIPbtnodeGetParent(node);
5808  }
5809 
5810  SCIPdebugMsg(scip, "updating done\n");
5811 
5812  return SCIP_OKAY;
5813 }
5814 
5815 /** updates the key of the first parent on the trace which comes from left */
5816 static
5817 void updateKeyOnTrace(
5818  SCIP_BTNODE* node, /**< node to start the trace */
5819  SCIP_Real key /**< update search key */
5820  )
5821 {
5822  assert(node != NULL);
5823 
5824  while( !SCIPbtnodeIsRoot(node) )
5825  {
5826  SCIP_BTNODE* parent;
5827 
5828  parent = SCIPbtnodeGetParent(node);
5829  assert(parent != NULL);
5830 
5831  if( SCIPbtnodeIsLeftchild(node) )
5832  {
5833  SCIP_NODEDATA* nodedata;
5834 
5835  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(parent);
5836  assert(nodedata != NULL);
5837 
5838  nodedata->key = key;
5839  return;
5840  }
5841 
5842  node = parent;
5843  }
5844 }
5845 
5846 
5847 /** deletes the given node and updates all envelops */
5848 static
5850  SCIP* scip, /**< SCIP data structure */
5851  SCIP_BT* tree, /**< binary tree */
5852  SCIP_BTNODE* node /**< node to be deleted */
5853  )
5854 {
5855  SCIP_BTNODE* parent;
5856  SCIP_BTNODE* grandparent;
5857  SCIP_BTNODE* sibling;
5858 
5859  assert(scip != NULL);
5860  assert(tree != NULL);
5861  assert(node != NULL);
5862 
5863  assert(SCIPbtnodeIsLeaf(node));
5864  assert(!SCIPbtnodeIsRoot(node));
5865 
5866  SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5867 
5868  parent = SCIPbtnodeGetParent(node);
5869  assert(parent != NULL);
5870  if( SCIPbtnodeIsLeftchild(node) )
5871  {
5872  sibling = SCIPbtnodeGetRightchild(parent);
5873  SCIPbtnodeSetRightchild(parent, NULL);
5874  }
5875  else
5876  {
5877  sibling = SCIPbtnodeGetLeftchild(parent);
5878  SCIPbtnodeSetLeftchild(parent, NULL);
5879  }
5880  assert(sibling != NULL);
5881 
5882  grandparent = SCIPbtnodeGetParent(parent);
5883 
5884  if( grandparent != NULL )
5885  {
5886  /* reset parent of sibling */
5887  SCIPbtnodeSetParent(sibling, grandparent);
5888 
5889  /* reset child of grandparent to sibling */
5890  if( SCIPbtnodeIsLeftchild(parent) )
5891  {
5892  SCIPbtnodeSetLeftchild(grandparent, sibling);
5893  }
5894  else
5895  {
5896  SCIP_NODEDATA* nodedata;
5897 
5898  assert(SCIPbtnodeIsRightchild(parent));
5899  SCIPbtnodeSetRightchild(grandparent, sibling);
5900 
5901  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(sibling);
5902 
5903  updateKeyOnTrace(grandparent, nodedata->key);
5904  }
5905 
5906  SCIP_CALL( updateEnvelop(scip, grandparent) );
5907  }
5908  else
5909  {
5910  SCIPbtnodeSetParent(sibling, NULL);
5911 
5912  SCIPbtSetRoot(tree, sibling);
5913  }
5914 
5915 
5916  SCIPbtnodeFree(tree, &parent);
5917 
5918  return SCIP_OKAY;
5919 }
5920 
5921 /** moves a node form the theta set into the lambda set and updates the envelops */
5922 static
5924  SCIP* scip, /**< SCIP data structure */
5925  SCIP_BT* tree, /**< binary tree */
5926  SCIP_BTNODE* node /**< node to move into the lambda set */
5927  )
5928 {
5929  SCIP_NODEDATA* nodedata;
5930 
5931  assert(scip != NULL);
5932  assert(tree != NULL);
5933  assert(node != NULL);
5934 
5935  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5936  assert(nodedata != NULL);
5937  assert(nodedata->intheta);
5938 
5939  /* move the contributions form the theta set into the lambda set */
5940  assert(nodedata->enveloptheta != -1);
5941  assert(nodedata->energytheta != -1);
5942  assert(nodedata->enveloplambda == -1);
5943  assert(nodedata->energylambda == -1);
5944  nodedata->enveloplambda = nodedata->enveloptheta;
5945  nodedata->energylambda = nodedata->energytheta;
5946 
5947  nodedata->enveloptheta = -1;
5948  nodedata->energytheta = 0;
5949  nodedata->intheta = FALSE;
5950 
5951  /* update the energy and envelop values on trace */
5952  SCIP_CALL( updateEnvelop(scip, node) );
5953 
5954  return SCIP_OKAY;
5955 }
5956 
5957 /** inserts a node into the theta set and update the envelops */
5958 static
5960  SCIP* scip, /**< SCIP data structure */
5961  SCIP_BT* tree, /**< binary tree */
5962  SCIP_BTNODE* node, /**< node to insert */
5963  SCIP_NODEDATA** nodedatas, /**< array of node data */
5964  int* nnodedatas /**< pointer to number of node data */
5965  )
5966 {
5967  /* if the tree is empty the node will be the root node */
5968  if( SCIPbtIsEmpty(tree) )
5969  {
5970  SCIPbtSetRoot(tree, node);
5971  }
5972  else
5973  {
5974  SCIP_NODEDATA* newnodedata;
5975  SCIP_NODEDATA* leafdata;
5976  SCIP_NODEDATA* nodedata;
5977  SCIP_BTNODE* leaf;
5978  SCIP_BTNODE* newnode;
5979  SCIP_BTNODE* parent;
5980 
5981  leaf = SCIPbtGetRoot(tree);
5982  assert(leaf != NULL);
5983 
5984  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5985  assert(leafdata != NULL);
5986 
5987  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5988  assert(nodedata != NULL);
5989  assert(nodedata->intheta);
5990 
5991  /* find the position to insert the node */
5992  while( !SCIPbtnodeIsLeaf(leaf) )
5993  {
5994  if( nodedata->key < leafdata->key )
5995  leaf = SCIPbtnodeGetLeftchild(leaf);
5996  else
5997  leaf = SCIPbtnodeGetRightchild(leaf);
5998 
5999  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6000  assert(leafdata != NULL);
6001  }
6002 
6003  assert(leaf != NULL);
6004  assert(leaf != node);
6005 
6006  /* create node data */
6007  SCIP_CALL( createNodedata(scip, &newnodedata) );
6008 
6009  /* create a new node */
6010  SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
6011  assert(newnode != NULL);
6012 
6013  /* store node data to be able to delete them latter */
6014  nodedatas[*nnodedatas] = newnodedata;
6015  (*nnodedatas)++;
6016 
6017  parent = SCIPbtnodeGetParent(leaf);
6018 
6019  if( parent != NULL )
6020  {
6021  SCIPbtnodeSetParent(newnode, parent);
6022 
6023  /* check if the node is the left child */
6024  if( SCIPbtnodeGetLeftchild(parent) == leaf )
6025  {
6026  SCIPbtnodeSetLeftchild(parent, newnode);
6027  }
6028  else
6029  {
6030  SCIPbtnodeSetRightchild(parent, newnode);
6031  }
6032  }
6033  else
6034  SCIPbtSetRoot(tree, newnode);
6035 
6036  if( nodedata->key < leafdata->key )
6037  {
6038  /* node is on the left */
6039  SCIPbtnodeSetLeftchild(newnode, node);
6040  SCIPbtnodeSetRightchild(newnode, leaf);
6041  newnodedata->key = nodedata->key;
6042  }
6043  else
6044  {
6045  /* leaf is on the left */
6046  SCIPbtnodeSetLeftchild(newnode, leaf);
6047  SCIPbtnodeSetRightchild(newnode, node);
6048  newnodedata->key = leafdata->key;
6049  }
6050 
6051  SCIPbtnodeSetParent(leaf, newnode);
6052  SCIPbtnodeSetParent(node, newnode);
6053  }
6054 
6055  /* update envelop */
6056  SCIP_CALL( updateEnvelop(scip, node) );
6057 
6058  return SCIP_OKAY;
6059 }
6060 
6061 /** returns the leaf responsible for the lambda energy */
6062 static
6064  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6065  )
6066 {
6067  SCIP_BTNODE* left;
6068  SCIP_BTNODE* right;
6069  SCIP_NODEDATA* nodedata;
6070  SCIP_NODEDATA* leftdata;
6071  SCIP_NODEDATA* rightdata;
6072 
6073  assert(node != NULL);
6074 
6075  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6076  assert(nodedata != NULL);
6077 
6078  /* check if the node is the (responsible) leaf */
6079  if( SCIPbtnodeIsLeaf(node) )
6080  {
6081  assert(!nodedata->intheta);
6082  return node;
6083  }
6084 
6085  left = SCIPbtnodeGetLeftchild(node);
6086  assert(left != NULL);
6087 
6088  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6089  assert(leftdata != NULL);
6090 
6091  right = SCIPbtnodeGetRightchild(node);
6092  assert(right != NULL);
6093 
6094  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6095  assert(rightdata != NULL);
6096 
6097  assert(nodedata->energylambda != -1);
6098  assert(rightdata->energytheta != -1);
6099 
6100  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6102 
6103  assert(leftdata->energytheta != -1);
6104  assert(rightdata->energylambda != -1);
6105  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6106 
6108 }
6109 
6110 /** returns the leaf responsible for the lambda envelop */
6111 static
6113  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6114  )
6115 {
6116  SCIP_BTNODE* left;
6117  SCIP_BTNODE* right;
6118  SCIP_NODEDATA* nodedata;
6119  SCIP_NODEDATA* leftdata;
6120  SCIP_NODEDATA* rightdata;
6121 
6122  assert(node != NULL);
6123 
6124  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6125  assert(nodedata != NULL);
6126 
6127  /* check if the node is the (responsible) leaf */
6128  if( SCIPbtnodeIsLeaf(node) )
6129  {
6130  assert(!nodedata->intheta);
6131  return node;
6132  }
6133 
6134  left = SCIPbtnodeGetLeftchild(node);
6135  assert(left != NULL);
6136 
6137  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6138  assert(leftdata != NULL);
6139 
6140  right = SCIPbtnodeGetRightchild(node);
6141  assert(right != NULL);
6142 
6143  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6144  assert(rightdata != NULL);
6145 
6146  assert(nodedata->enveloplambda != -1);
6147  assert(rightdata->energytheta != -1);
6148 
6149  /* check if the left or right child is the one defining the envelop for the lambda set */
6150  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6152  else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6153  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6155 
6156  assert(rightdata->enveloplambda != -1);
6157  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6158 
6160 }
6161 
6162 
6163 /** reports all elements from set theta to generate a conflicting set */
6164 static
6165 void collectThetaSubtree(
6166  SCIP_BTNODE* node, /**< node within a theta subtree */
6167  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6168  int* nelements, /**< pointer to store the number of elements in omegaset */
6169  int* est, /**< pointer to store the earliest start time of the omega set */
6170  int* lct, /**< pointer to store the latest start time of the omega set */
6171  int* energy /**< pointer to store the energy of the omega set */
6172  )
6173 {
6174  SCIP_NODEDATA* nodedata;
6175 
6176  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6177  assert(nodedata != NULL);
6178 
6179  if( !SCIPbtnodeIsLeaf(node) )
6180  {
6181  collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6182  collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6183  }
6184  else if( nodedata->intheta )
6185  {
6186  assert(nodedata->var != NULL);
6187  SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6188 
6189  omegaset[*nelements] = node;
6190  (*est) = MIN(*est, nodedata->est);
6191  (*lct) = MAX(*lct, nodedata->lct);
6192  (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6193  (*nelements)++;
6194  }
6195 }
6196 
6197 
6198 /** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6199 static
6200 void traceThetaEnvelop(
6201  SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6202  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6203  int* nelements, /**< pointer to store the number of elements in omegaset */
6204  int* est, /**< pointer to store the earliest start time of the omega set */
6205  int* lct, /**< pointer to store the latest start time of the omega set */
6206  int* energy /**< pointer to store the energy of the omega set */
6207  )
6208 {
6209  assert(node != NULL);
6210 
6211  if( SCIPbtnodeIsLeaf(node) )
6212  {
6213  collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6214  }
6215  else
6216  {
6217  SCIP_BTNODE* left;
6218  SCIP_BTNODE* right;
6219  SCIP_NODEDATA* nodedata;
6220  SCIP_NODEDATA* leftdata;
6221  SCIP_NODEDATA* rightdata;
6222 
6223  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6224  assert(nodedata != NULL);
6225 
6226 
6227  left = SCIPbtnodeGetLeftchild(node);
6228  assert(left != NULL);
6229 
6230  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6231  assert(leftdata != NULL);
6232 
6233  right = SCIPbtnodeGetRightchild(node);
6234  assert(right != NULL);
6235 
6236  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6237  assert(rightdata != NULL);
6238 
6239  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6240  assert(nodedata != NULL);
6241 
6242  assert(nodedata->enveloptheta != -1);
6243  assert(rightdata->energytheta != -1);
6244 
6245  if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6246  {
6247  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6248  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6249  }
6250  else
6251  {
6252  assert(rightdata->enveloptheta != -1);
6253  assert(nodedata->enveloptheta == rightdata->enveloptheta);
6254  traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6255  }
6256  }
6257 }
6258 
6259 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6260 static
6261 void traceLambdaEnergy(
6262  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6263  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6264  int* nelements, /**< pointer to store the number of elements in omega set */
6265  int* est, /**< pointer to store the earliest start time of the omega set */
6266  int* lct, /**< pointer to store the latest start time of the omega set */
6267  int* energy /**< pointer to store the energy of the omega set */
6268  )
6269 {
6270  SCIP_BTNODE* left;
6271  SCIP_BTNODE* right;
6272  SCIP_NODEDATA* nodedata;
6273  SCIP_NODEDATA* leftdata;
6274  SCIP_NODEDATA* rightdata;
6275 
6276  assert(node != NULL);
6277 
6278  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6279  assert(nodedata != NULL);
6280 
6281  /* check if the node is a leaf */
6282  if( SCIPbtnodeIsLeaf(node) )
6283  return;
6284 
6285  left = SCIPbtnodeGetLeftchild(node);
6286  assert(left != NULL);
6287 
6288  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6289  assert(leftdata != NULL);
6290 
6291  right = SCIPbtnodeGetRightchild(node);
6292  assert(right != NULL);
6293 
6294  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6295  assert(rightdata != NULL);
6296 
6297  assert(nodedata->energylambda != -1);
6298  assert(rightdata->energytheta != -1);
6299 
6300  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6301  {
6302  traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6303  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6304  }
6305  else
6306  {
6307  assert(leftdata->energytheta != -1);
6308  assert(rightdata->energylambda != -1);
6309  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6310 
6311  collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6312  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6313  }
6314 }
6315 
6316 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6317 static
6318 void traceLambdaEnvelop(
6319  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6320  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6321  int* nelements, /**< pointer to store the number of elements in omega set */
6322  int* est, /**< pointer to store the earliest start time of the omega set */
6323  int* lct, /**< pointer to store the latest start time of the omega set */
6324  int* energy /**< pointer to store the energy of the omega set */
6325  )
6326 {
6327  SCIP_BTNODE* left;
6328  SCIP_BTNODE* right;
6329  SCIP_NODEDATA* nodedata;
6330  SCIP_NODEDATA* leftdata;
6331  SCIP_NODEDATA* rightdata;
6332 
6333  assert(node != NULL);
6334 
6335  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6336  assert(nodedata != NULL);
6337 
6338  /* check if the node is a leaf */
6339  if( SCIPbtnodeIsLeaf(node) )
6340  {
6341  assert(!nodedata->intheta);
6342  return;
6343  }
6344 
6345  left = SCIPbtnodeGetLeftchild(node);
6346  assert(left != NULL);
6347 
6348  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6349  assert(leftdata != NULL);
6350 
6351  right = SCIPbtnodeGetRightchild(node);
6352  assert(right != NULL);
6353 
6354  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6355  assert(rightdata != NULL);
6356 
6357  assert(nodedata->enveloplambda != -1);
6358  assert(rightdata->energytheta != -1);
6359 
6360  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6361  {
6362  traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6363  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6364  }
6365  else
6366  {
6367  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6368  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6369  {
6370  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6371  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6372  }
6373  else
6374  {
6375  assert(rightdata->enveloplambda != -1);
6376  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6377  traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6378  }
6379  }
6380 }
6381 
6382 /** compute the energy contribution by job which corresponds to the given leaf */
6383 static
6385  SCIP_BTNODE* node /**< leaf */
6386  )
6387 {
6388  SCIP_NODEDATA* nodedata;
6389  int duration;
6390 
6391  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6392  assert(nodedata != NULL);
6393  assert(nodedata->var != NULL);
6394 
6395  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6396  assert(duration > 0);
6397 
6398  SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6400  SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6401 
6402  /* return energy which is contributed by the start time variable */
6403  return nodedata->demand * duration;
6404 }
6405 
6406 /** comparison method for two node data w.r.t. the earliest start time */
6407 static
6408 SCIP_DECL_SORTPTRCOMP(compNodeEst)
6410  int est1;
6411  int est2;
6412 
6413  est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6414  est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6415 
6416  return (est1 - est2);
6417 }
6418 
6419 /** comparison method for two node data w.r.t. the latest completion time */
6420 static
6421 SCIP_DECL_SORTPTRCOMP(compNodedataLct)
6423  int lct1;
6424  int lct2;
6425 
6426  lct1 = ((SCIP_NODEDATA*)elem1)->lct;
6427  lct2 = ((SCIP_NODEDATA*)elem2)->lct;
6428 
6429  return (lct1 - lct2);
6430 }
6431 
6432 
6433 /** an overload was detected; initialized conflict analysis, add an initial reason
6434  *
6435  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6436  */
6437 static
6439  SCIP* scip, /**< SCIP data structure */
6440  SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6441  int capacity, /**< cumulative capacity */
6442  int nleaves, /**< number of responsible leaves */
6443  int est, /**< earliest start time of the ...... */
6444  int lct, /**< latest completly time of the .... */
6445  int reportedenergy, /**< energy which already reported */
6446  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6447  int shift, /**< shift applied to all jobs before adding them to the tree */
6448  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6449  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6450  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6451  )
6452 {
6453  int energy;
6454  int j;
6455 
6456  /* do nothing if conflict analysis is not applicable */
6458  return SCIP_OKAY;
6459 
6460  SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6461 
6462  /* compute energy of initial time window */
6463  energy = (lct - est) * capacity;
6464 
6465  /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6466  SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6467 
6468  /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6469  * thereby, compute the time window of interest
6470  */
6471  for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6472  {
6473  SCIP_NODEDATA* nodedata;
6474 
6475  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6476  assert(nodedata != NULL);
6477 
6478  reportedenergy += computeEnergyContribution(leaves[j]);
6479 
6480  /* adjust energy if the earliest start time decrease */
6481  if( nodedata->est < est )
6482  {
6483  est = nodedata->est;
6484  energy = (lct - est) * capacity;
6485  }
6486  }
6487  assert(reportedenergy > energy);
6488 
6489  SCIPdebugMsg(scip, "time window [%d,%d) available energy %d, required energy %d\n", est, lct, energy, reportedenergy);
6490 
6491  /* initialize conflict analysis */
6493 
6494  /* flip earliest start time and latest completion time */
6495  if( !propest )
6496  {
6497  SCIPswapInts(&est, &lct);
6498 
6499  /* shift earliest start time and latest completion time */
6500  lct = shift - lct;
6501  est = shift - est;
6502  }
6503  else
6504  {
6505  /* shift earliest start time and latest completion time */
6506  lct = lct + shift;
6507  est = est + shift;
6508  }
6509 
6510  nleaves = j;
6511 
6512  /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6513  * overloaded
6514  */
6515  for( j = nleaves-1; j >= 0; --j )
6516  {
6517  SCIP_NODEDATA* nodedata;
6518 
6519  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6520  assert(nodedata != NULL);
6521  assert(nodedata->var != NULL);
6522 
6523  /* check if bound widening should be used */
6524  if( usebdwidening )
6525  {
6526  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6527  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6528  }
6529  else
6530  {
6531  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6532  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6533  }
6534 
6535  if( explanation != NULL )
6536  explanation[nodedata->idx] = TRUE;
6537  }
6538 
6539  (*initialized) = TRUE;
6540 
6541  return SCIP_OKAY;
6542 }
6543 
6544 /** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6545  * responsible interval bounds in *est_omega and *lct_omega
6546  */
6547 static
6548 int computeEstOmegaset(
6549  SCIP* scip, /**< SCIP data structure */
6550  int duration, /**< duration of the job to move */
6551  int demand, /**< demand of the job to move */
6552  int capacity, /**< cumulative capacity */
6553  int est, /**< earliest start time of the omega set */
6554  int lct, /**< latest start time of the omega set */
6555  int energy /**< energy of the omega set */
6556  )
6557 {
6558  int newest;
6559 
6560  newest = 0;
6561 
6562  assert(scip != NULL);
6563 
6564  if( energy > (capacity - demand) * (lct - est) )
6565  {
6566  if( energy + demand * duration > capacity * (lct - est) )
6567  {
6568  newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6569  newest += est;
6570  }
6571  }
6572 
6573  return newest;
6574 }
6575 
6576 /** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6577  *
6578  * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6579  * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6580  */
6581 static
6583  SCIP* scip, /**< SCIP data structure */
6584  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6585  SCIP_CONS* cons, /**< constraint which is propagated */
6586  SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6587  SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6588  int capacity, /**< cumulative capacity */
6589  int ncands, /**< number of candidates */
6590  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6591  int shift, /**< shift applied to all jobs before adding them to the tree */
6592  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6593  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6594  int* nchgbds, /**< pointer to store the number of bound changes */
6595  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6596  )
6597 {
6598  SCIP_NODEDATA* rootdata;
6599  int j;
6600 
6601  assert(!SCIPbtIsEmpty(tree));
6602 
6603  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6604  assert(rootdata != NULL);
6605 
6606  /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6607  for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6608  {
6609  SCIP_NODEDATA* nodedata;
6610 
6611  if( SCIPbtnodeIsRoot(leaves[j]) )
6612  break;
6613 
6614  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6615  assert(nodedata->est != -1);
6616 
6617  /* check if the root lambda envelop exeeds the available capacity */
6618  while( !(*cutoff) && rootdata->enveloplambda > capacity * nodedata->lct )
6619  {
6620  SCIP_BTNODE** omegaset;
6621  SCIP_BTNODE* leaf;
6622  SCIP_NODEDATA* leafdata;
6623  int nelements;
6624  int energy;
6625  int newest;
6626  int est;
6627  int lct;
6628 
6629  assert(!(*cutoff));
6630 
6631  /* find responsible leaf for the lambda envelope */
6633  assert(leaf != NULL);
6634  assert(SCIPbtnodeIsLeaf(leaf));
6635 
6636  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6637  assert(leafdata != NULL);
6638  assert(!leafdata->intheta);
6639  assert(leafdata->duration > 0);
6640  assert(leafdata->est >= 0);
6641 
6642  /* check if the job has to be removed since its latest completion is to large */
6643  if( leafdata->est + leafdata->duration >= nodedata->lct )
6644  {
6645  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6646 
6647  /* the root might changed therefore we need to collect the new root node data */
6648  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6649  assert(rootdata != NULL);
6650 
6651  continue;
6652  }
6653 
6654  /* compute omega set */
6655  SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6656 
6657  nelements = 0;
6658  est = INT_MAX;
6659  lct = INT_MIN;
6660  energy = 0;
6661 
6662  /* collect the omega set from theta set */
6663  traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6664  assert(nelements > 0);
6665  assert(nelements < ncands);
6666 
6667  newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6668 
6669  /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6670  if( newest > lct )
6671  {
6672  SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6673 
6674  /* analyze over load */
6675  SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6676  conshdlrdata->usebdwidening, initialized, explanation) );
6677  (*cutoff) = TRUE;
6678 
6679  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6680  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6681  }
6682  else if( newest > 0 )
6683  {
6684  SCIP_Bool infeasible;
6685  SCIP_Bool tightened;
6686  INFERINFO inferinfo;
6687 
6688  if( propest )
6689  {
6690  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6691  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6692 
6693  SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6694  SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6695 
6696  SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6697  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6698 
6699  /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6701  }
6702  else
6703  {
6704  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6705  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6706 
6707  SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6708  SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6709 
6710  SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6711  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6712 
6713  /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6715  }
6716 
6717  /* adjust the earliest start time */
6718  if( tightened )
6719  {
6720  leafdata->est = newest;
6721  (*nchgbds)++;
6722  }
6723 
6724  if( infeasible )
6725  {
6726  /* initialize conflict analysis if conflict analysis is applicable */
6728  {
6729  int i;
6730 
6731  SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6732 
6734 
6735  /* add lower and upper bound of variable which leads to the infeasibilty */
6736  SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6737  SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6738 
6739  if( explanation != NULL )
6740  explanation[leafdata->idx] = TRUE;
6741 
6742  /* add lower and upper bound of variable which lead to the infeasibilty */
6743  for( i = 0; i < nelements; ++i )
6744  {
6745  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6746  assert(nodedata != NULL);
6747 
6748  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6749  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6750 
6751  if( explanation != NULL )
6752  explanation[nodedata->idx] = TRUE;
6753  }
6754 
6755  (*initialized) = TRUE;
6756  }
6757 
6758  (*cutoff) = TRUE;
6759 
6760  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6761  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6762  }
6763  }
6764 
6765  /* free omegaset array */
6766  SCIPfreeBufferArray(scip, &omegaset);
6767 
6768  /* delete responsible leaf from lambda */
6769  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6770 
6771  /* the root might changed therefore we need to collect the new root node data */
6772  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6773  assert(rootdata != NULL);
6774  }
6775 
6776  /* move current job j from the theta set into the lambda set */
6777  SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6778  }
6779 
6780  return SCIP_OKAY;
6781 }
6782 
6783 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6784  *
6785  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6786  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6787  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6788  */
6789 static
6791  SCIP* scip, /**< SCIP data structure */
6792  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6793  int nvars, /**< number of start time variables (activities) */
6794  SCIP_VAR** vars, /**< array of start time variables */
6795  int* durations, /**< array of durations */
6796  int* demands, /**< array of demands */
6797  int capacity, /**< cumulative capacity */
6798  int hmin, /**< left bound of time axis to be considered (including hmin) */
6799  int hmax, /**< right bound of time axis to be considered (not including hmax) */
6800  SCIP_CONS* cons, /**< constraint which is propagated */
6801  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6802  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6803  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6804  int* nchgbds, /**< pointer to store the number of bound changes */
6805  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6806  )
6807 {
6808  SCIP_NODEDATA** nodedatas;
6809  SCIP_BTNODE** leaves;
6810  SCIP_BT* tree;
6811 
6812  int totalenergy;
6813  int nnodedatas;
6814  int ninsertcands;
6815  int ncands;
6816 
6817  int shift;
6818  int j;
6819 
6820  assert(scip != NULL);
6821  assert(cons != NULL);
6822  assert(initialized != NULL);
6823  assert(cutoff != NULL);
6824  assert(*cutoff == FALSE);
6825 
6826  SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6827 
6828  SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6829  SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6830 
6831  ncands = 0;
6832  totalenergy = 0;
6833 
6834  SCIP_CALL( SCIPbtCreate(&tree, SCIPblkmem(scip)) );
6835 
6836  /* compute the shift which we apply to compute .... latest completion time of all jobs */
6837  if( propest )
6838  shift = 0;
6839  else
6840  {
6841  shift = 0;
6842 
6843  /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6844  * earliest start time propagation to handle the latest completion times
6845  */
6846  for( j = 0; j < nvars; ++j )
6847  {
6848  int lct;
6849 
6850  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6851  shift = MAX(shift, lct);
6852  }
6853  }
6854 
6855  /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6856  * horizon
6857  */
6858  for( j = 0; j < nvars; ++j )
6859  {
6860  SCIP_NODEDATA* nodedata;
6861  SCIP_VAR* var;
6862  int duration;
6863  int leftadjust;
6864  int rightadjust;
6865  int energy;
6866  int est;
6867  int lct;
6868 
6869  var = vars[j];
6870  assert(var != NULL);
6871 
6872  duration = durations[j];
6873  assert(duration > 0);
6874 
6875  leftadjust = 0;
6876  rightadjust = 0;
6877 
6878  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
6879  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6880 
6881  /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6882  * effective horizon [hmin,hmax)
6883  */
6884  if( conshdlrdata->useadjustedjobs )
6885  {
6886  if( est < hmin )
6887  {
6888  leftadjust = (hmin - est);
6889  est = hmin;
6890  }
6891  if( lct > hmax )
6892  {
6893  rightadjust = (lct - hmax);
6894  lct = hmax;
6895  }
6896 
6897  /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6898  * with the effective time horizon
6899  */
6900  if( duration - leftadjust - rightadjust <= 0 )
6901  continue;
6902  }
6903  else if( est < hmin || lct > hmax )
6904  continue;
6905 
6906  energy = demands[j] * (duration - leftadjust - rightadjust);
6907  assert(energy > 0);
6908 
6909  totalenergy += energy;
6910 
6911  /* flip earliest start time and latest completion time */
6912  if( !propest )
6913  {
6914  SCIPswapInts(&est, &lct);
6915 
6916  /* shift earliest start time and latest completion time */
6917  lct = shift - lct;
6918  est = shift - est;
6919  }
6920  else
6921  {
6922  /* shift earliest start time and latest completion time */
6923  lct = lct - shift;
6924  est = est - shift;
6925  }
6926  assert(est < lct);
6927  assert(est >= 0);
6928  assert(lct >= 0);
6929 
6930  /* create search node data */
6931  SCIP_CALL( createNodedata(scip, &nodedata) );
6932 
6933  /* initialize search node data */
6934  /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6935  nodedata->key = est + j / (2.0 * nvars);
6936  nodedata->var = var;
6937  nodedata->est = est;
6938  nodedata->lct = lct;
6939  nodedata->demand = demands[j];
6940  nodedata->duration = duration;
6941  nodedata->leftadjust = leftadjust;
6942  nodedata->rightadjust = rightadjust;
6943 
6944  /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6945  * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6946  * particular time interval [a,b] against the time interval [0,b].
6947  */
6948  nodedata->enveloptheta = capacity * est + energy;
6949  nodedata->energytheta = energy;
6950  nodedata->enveloplambda = -1;
6951  nodedata->energylambda = -1;
6952 
6953  nodedata->idx = j;
6954  nodedata->intheta = TRUE;
6955 
6956  nodedatas[ncands] = nodedata;
6957  ncands++;
6958  }
6959 
6960  nnodedatas = ncands;
6961 
6962  /* sort (non-decreasing) the jobs w.r.t. latest completion times */
6963  SCIPsortPtr((void**)nodedatas, compNodedataLct, ncands);
6964 
6965  ninsertcands = 0;
6966 
6967  /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
6968  * the root envelop detects an overload
6969  */
6970  for( j = 0; j < ncands; ++j )
6971  {
6972  SCIP_BTNODE* leaf;
6973  SCIP_NODEDATA* rootdata;
6974 
6975  /* check if the new job opens a time window which size is so large that it offers more energy than the total
6976  * energy of all candidate jobs. If so we skip that one.
6977  */
6978  if( (nodedatas[j]->lct - nodedatas[j]->est) * capacity >= totalenergy )
6979  {
6980  /* set the earliest start time to minus one to mark that candidate to be not used */
6981  nodedatas[j]->est = -1;
6982  continue;
6983  }
6984 
6985  /* create search node */
6986  SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)nodedatas[j]) );
6987 
6988  /* insert new node into the theta set and updete the envelops */
6989  SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, &nnodedatas) );
6990  assert(nnodedatas <= 2*nvars);
6991 
6992  /* move the inserted candidates together */
6993  leaves[ninsertcands] = leaf;
6994  ninsertcands++;
6995 
6996  assert(!SCIPbtIsEmpty(tree));
6997  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6998  assert(rootdata != NULL);
6999 
7000  /* check if the theta set envelops exceeds the available capacity */
7001  if( rootdata->enveloptheta > capacity * nodedatas[j]->lct )
7002  {
7003  SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[j]->lct, j);
7004  (*cutoff) = TRUE;
7005 
7006  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
7007  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverload++ );
7008 
7009  break;
7010  }
7011  }
7012 
7013  /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
7014  if( *cutoff )
7015  {
7016  int glbenery;
7017  int est;
7018  int lct;
7019 
7020  glbenery = 0;
7021  est = nodedatas[j]->est;
7022  lct = nodedatas[j]->lct;
7023 
7024  /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
7025  * which led to an overload
7026  */
7027  for( j = j+1; j < ncands; ++j )
7028  {
7029  SCIP_NODEDATA* nodedata;
7030  int duration;
7031  int glbest;
7032  int glblct;
7033 
7034  nodedata = nodedatas[j];
7035  assert(nodedata != NULL);
7036 
7037  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
7038 
7039  /* get latest start time */
7040  glbest = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(nodedata->var));
7041  glblct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
7042 
7043  /* check if parts of the jobs run with the time window defined by the last inserted job */
7044  if( glbest < est )
7045  duration -= (est - glbest);
7046 
7047  if( glblct > lct )
7048  duration -= (glblct - lct);
7049 
7050  if( duration > 0 )
7051  {
7052  glbenery += nodedata->demand * duration;
7053 
7054  if( explanation != NULL )
7055  explanation[nodedata->idx] = TRUE;
7056  }
7057  }
7058 
7059  /* analyze the overload */
7060  SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7061  conshdlrdata->usebdwidening, initialized, explanation) );
7062  }
7063  else if( ninsertcands > 1 && conshdlrdata->efinfer )
7064  {
7065  /* if we have more than one job insterted and edge-finding should be performed we do it */
7066  SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7067  propest, shift, initialized, explanation, nchgbds, cutoff) );
7068  }
7069 
7070  /* free the search nodes data */
7071  for( j = nnodedatas - 1; j >= 0; --j )
7072  {
7073  freeNodedata(scip, &nodedatas[j]);
7074  }
7075 
7076  /* free theta tree */
7077  SCIPbtFree(&tree);
7078 
7079  /* free buffer arrays */
7080  SCIPfreeBufferArray(scip, &leaves);
7081  SCIPfreeBufferArray(scip, &nodedatas);
7082 
7083  return SCIP_OKAY;
7084 }
7085 
7086 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7087  *
7088  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7089  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7090  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7091  */
7092 static
7094  SCIP* scip, /**< SCIP data structure */
7095  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7096  int nvars, /**< number of start time variables (activities) */
7097  SCIP_VAR** vars, /**< array of start time variables */
7098  int* durations, /**< array of durations */
7099  int* demands, /**< array of demands */
7100  int capacity, /**< cumulative capacity */
7101  int hmin, /**< left bound of time axis to be considered (including hmin) */
7102  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7103  SCIP_CONS* cons, /**< constraint which is propagated */
7104  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7105  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7106  int* nchgbds, /**< pointer to store the number of bound changes */
7107  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7108  )
7109 {
7110  /* check if a cutoff was already detected */
7111  if( (*cutoff) )
7112  return SCIP_OKAY;
7113 
7114  /* check if at least the basic overload checking should be preformed */
7115  if( !conshdlrdata->efcheck )
7116  return SCIP_OKAY;
7117 
7118  /* check for overload, which may result in a cutoff */
7119  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7120  cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7121 
7122  /* check if a cutoff was detected */
7123  if( (*cutoff) )
7124  return SCIP_OKAY;
7125 
7126  /* check if bound should be infer */
7127  if( !conshdlrdata->efinfer )
7128  return SCIP_OKAY;
7129 
7130  /* check for overload, which may result in a cutoff */
7131  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7132  cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7133 
7134  return SCIP_OKAY;
7135 }
7136 
7137 /** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7138  * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7139  * event points
7140  */
7141 static
7143  SCIP* scip, /**< SCIP data structure */
7144  int nvars, /**< number of start time variables (activities) */
7145  SCIP_VAR** vars, /**< array of start time variables */
7146  int* durations, /**< array of durations */
7147  int* demands, /**< array of demands */
7148  int capacity, /**< cumulative capacity */
7149  int hmin, /**< left bound of time axis to be considered (including hmin) */
7150  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7151  SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7152  )
7153 {
7154 
7155  SCIP_VAR* var;
7156  int* starttimes; /* stores when each job is starting */
7157  int* endtimes; /* stores when each job ends */
7158  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7159  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7160 
7161  int lb;
7162  int ub;
7163  int freecapacity; /* remaining capacity */
7164  int curtime; /* point in time which we are just checking */
7165  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7166  int njobs;
7167  int j;
7168 
7169  assert(scip != NULL);
7170  assert(redundant != NULL);
7171 
7172  (*redundant) = TRUE;
7173 
7174  /* if no activities are associated with this cumulative then this constraint is redundant */
7175  if( nvars == 0 )
7176  return SCIP_OKAY;
7177 
7178  assert(vars != NULL);
7179 
7180  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7181  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7182  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7183  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7184 
7185  njobs = 0;
7186 
7187  /* assign variables, start and endpoints to arrays */
7188  for( j = 0; j < nvars; ++j )
7189  {
7190  assert(durations[j] > 0);
7191  assert(demands[j] > 0);
7192 
7193  var = vars[j];
7194  assert(var != NULL);
7195 
7196  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7197  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7198 
7199  /* check if jobs runs completely outside of the effective time horizon */
7200  if( lb >= hmax || ub + durations[j] <= hmin )
7201  continue;
7202 
7203  starttimes[njobs] = MAX(lb, hmin);
7204  startindices[njobs] = j;
7205 
7206  endtimes[njobs] = MIN(ub + durations[j], hmax);
7207  endindices[njobs] = j;
7208  assert(starttimes[njobs] <= endtimes[njobs]);
7209  njobs++;
7210  }
7211 
7212  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7213  SCIPsortIntInt(starttimes, startindices, njobs);
7214  SCIPsortIntInt(endtimes, endindices, njobs);
7215 
7216  endindex = 0;
7217  freecapacity = capacity;
7218 
7219  /* check each start point of a job whether the capacity is violated or not */
7220  for( j = 0; j < njobs; ++j )
7221  {
7222  curtime = starttimes[j];
7223 
7224  /* stop checking, if time point is above hmax */
7225  if( curtime >= hmax )
7226  break;
7227 
7228  /* subtract all capacity needed up to this point */
7229  freecapacity -= demands[startindices[j]];
7230  while( j+1 < njobs && starttimes[j+1] == curtime )
7231  {
7232  ++j;
7233  freecapacity -= demands[startindices[j]];
7234  }
7235 
7236  /* free all capacity usages of jobs the are no longer running */
7237  while( endtimes[endindex] <= curtime )
7238  {
7239  freecapacity += demands[endindices[endindex]];
7240  ++endindex;
7241  }
7242  assert(freecapacity <= capacity);
7243 
7244  /* check freecapacity to be smaller than zero */
7245  if( freecapacity < 0 && curtime >= hmin )
7246  {
7247  (*redundant) = FALSE;
7248  break;
7249  }
7250  } /*lint --e{850}*/
7251 
7252  /* free all buffer arrays */
7253  SCIPfreeBufferArray(scip, &endindices);
7254  SCIPfreeBufferArray(scip, &startindices);
7255  SCIPfreeBufferArray(scip, &endtimes);
7256  SCIPfreeBufferArray(scip, &starttimes);
7257 
7258  return SCIP_OKAY;
7259 }
7260 
7261 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7262  * completion time
7263  */
7264 static
7266  SCIP* scip, /**< SCIP data structure */
7267  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7268  SCIP_PROFILE* profile, /**< resource profile */
7269  int nvars, /**< number of variables (jobs) */
7270  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7271  int* durations, /**< array containing corresponding durations */
7272  int* demands, /**< array containing corresponding demands */
7273  int capacity, /**< cumulative capacity */
7274  int hmin, /**< left bound of time axis to be considered (including hmin) */
7275  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7276  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7277  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7278  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7279  )
7280 {
7281  int v;
7282 
7283  /* insert all cores */
7284  for( v = 0; v < nvars; ++v )
7285  {
7286  SCIP_VAR* var;
7287  SCIP_Bool infeasible;
7288  int duration;
7289  int demand;
7290  int begin;
7291  int end;
7292  int est;
7293  int lst;
7294  int pos;
7295 
7296  var = vars[v];
7297  assert(var != NULL);
7298  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(var)));
7299  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(var)));
7300 
7301  duration = durations[v];
7302  assert(duration > 0);
7303 
7304  demand = demands[v];
7305  assert(demand > 0);
7306 
7307  /* collect earliest and latest start time */
7308  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7309  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7310 
7311  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7312  if( lst + duration <= hmin || est >= hmax )
7313  continue;
7314 
7315  /* compute core interval w.r.t. effective time horizon */
7316  begin = MAX(hmin, lst);
7317  end = MIN(hmax, est + duration);
7318 
7319  /* check if a core exists */
7320  if( begin >= end )
7321  continue;
7322 
7323  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7324  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7325 
7326  /* insert the core into core resource profile (complexity O(log n)) */
7327  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7328 
7329  /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7330  if( infeasible )
7331  {
7332  assert(begin <= SCIPprofileGetTime(profile, pos));
7333  assert(end > SCIPprofileGetTime(profile, pos));
7334 
7335  /* use conflict analysis to analysis the core insertion which was infeasible */
7336  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7337  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7338 
7339  if( explanation != NULL )
7340  explanation[v] = TRUE;
7341 
7342  (*cutoff) = TRUE;
7343 
7344  /* for the statistic we count the number of times a cutoff was detected due the time-time */
7345  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
7346 
7347  break;
7348  }
7349  }
7350 
7351  return SCIP_OKAY;
7352 }
7353 
7354 /** propagate the cumulative condition */
7355 static
7357  SCIP* scip, /**< SCIP data structure */
7358  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7359  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7360  int nvars, /**< number of start time variables (activities) */
7361  SCIP_VAR** vars, /**< array of start time variables */
7362  int* durations, /**< array of durations */
7363  int* demands, /**< array of demands */
7364  int capacity, /**< cumulative capacity */
7365  int hmin, /**< left bound of time axis to be considered (including hmin) */
7366  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7367  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7368  int* nchgbds, /**< pointer to store the number of bound changes */
7369  SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7370  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7371  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7372  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7373  )
7374 {
7375  SCIP_PROFILE* profile;
7376 
7377  SCIP_RETCODE retcode = SCIP_OKAY;
7378 
7379  assert(nchgbds != NULL);
7380  assert(initialized != NULL);
7381  assert(cutoff != NULL);
7382  assert(!(*cutoff));
7383 
7384  /**@todo avoid always sorting the variable array */
7385 
7386  /* check if the constraint is redundant */
7387  SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7388 
7389  if( *redundant )
7390  return SCIP_OKAY;
7391 
7392  /* create an empty resource profile for profiling the cores of the jobs */
7393  SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7394 
7395  /* create core profile (compulsory parts) */
7396  SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7397  initialized, explanation, cutoff), TERMINATE );
7398 
7399  /* propagate the job cores until nothing else can be detected */
7400  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7401  {
7402  SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7403  nchgbds, initialized, explanation, cutoff), TERMINATE );
7404  }
7405 
7406  /* run edge finding propagator */
7407  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7408  {
7409  SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7410  cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7411  }
7412 
7413  /* run time-table edge-finding propagator */
7414  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7415  {
7416  SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7417  nchgbds, initialized, explanation, cutoff), TERMINATE );
7418  }
7419  /* free resource profile */
7420 TERMINATE:
7421  SCIPprofileFree(&profile);
7422 
7423  return retcode;
7424 }
7425 
7426 /** propagate the cumulative constraint */
7427 static
7429  SCIP* scip, /**< SCIP data structure */
7430  SCIP_CONS* cons, /**< constraint to propagate */
7431  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7432  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7433  int* nchgbds, /**< pointer to store the number of bound changes */
7434  int* ndelconss, /**< pointer to store the number of deleted constraints */
7435  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7436  )
7437 {
7438  SCIP_CONSDATA* consdata;
7439  SCIP_Bool initialized;
7440  SCIP_Bool redundant;
7441  int oldnchgbds;
7442 
7443  assert(scip != NULL);
7444  assert(cons != NULL);
7445 
7446  consdata = SCIPconsGetData(cons);
7447  assert(consdata != NULL);
7448 
7449  oldnchgbds = *nchgbds;
7450  initialized = FALSE;
7451  redundant = FALSE;
7452 
7453  if( SCIPconsIsDeleted(cons) )
7454  {
7455  assert(SCIPinProbing(scip));
7456  return SCIP_OKAY;
7457  }
7458 
7459  /* if the constraint marked to be propagated, do nothing */
7460  if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7461  return SCIP_OKAY;
7462 
7463  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7464  consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7465  consdata->hmin, consdata->hmax, cons,
7466  nchgbds, &redundant, &initialized, NULL, cutoff) );
7467 
7468  if( redundant )
7469  {
7470  SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7471  SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7472 
7473  if( !SCIPinProbing(scip) )
7474  {
7475  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7476  (*ndelconss)++;
7477  }
7478  }
7479  else
7480  {
7481  if( initialized )
7482  {
7483  /* run conflict analysis since it was initialized */
7484  assert(*cutoff == TRUE);
7485  SCIPdebugMsg(scip, "start conflict analysis\n");
7486  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7487  }
7488 
7489  /* if successful, reset age of constraint */
7490  if( *cutoff || *nchgbds > oldnchgbds )
7491  {
7492  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7493  }
7494  else
7495  {
7496  /* mark the constraint to be propagated */
7497  consdata->propagated = TRUE;
7498  }
7499  }
7500 
7501  return SCIP_OKAY;
7502 }
7503 
7504 /** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7505  * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7506  * be realize as domain reduction. Otherwise we do nothing
7507  */
7508 static
7510  SCIP* scip, /**< SCIP data structure */
7511  SCIP_VAR** vars, /**< problem variables */
7512  int nvars, /**< number of problem variables */
7513  int probingpos, /**< variable number to apply probing on */
7514  SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7515  SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7516  SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7517  SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7518  SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7519  SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7520  SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7521  SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7522  SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7523  SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7524  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7525  SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7526  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7527  )
7528 {
7529  SCIP_VAR* var;
7530  SCIP_Bool tightened;
7531 
7532  assert(probingpos >= 0);
7533  assert(probingpos < nvars);
7534  assert(success != NULL);
7535  assert(cutoff != NULL);
7536 
7537  var = vars[probingpos];
7538  assert(var != NULL);
7539  assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7540  assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7541  assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7542  assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7543 
7544  (*success) = FALSE;
7545 
7546  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7547  return SCIP_OKAY;
7548 
7549  /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7550  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7551  leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7552 
7553  if( (*cutoff) )
7554  {
7555  /* note that cutoff may occur if presolving has not been executed fully */
7556  SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7557 
7558  if( tightened )
7559  {
7560  (*success) =TRUE;
7561  (*nfixedvars)++;
7562  }
7563 
7564  return SCIP_OKAY;
7565  }
7566 
7567  /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7568  * presolving has not been executed fully
7569  */
7570  if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7571  {
7572  /* note that cutoff may occur if presolving has not been executed fully */
7573  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7574 
7575  if( tightened )
7576  {
7577  (*success) = TRUE;
7578  (*nfixedvars)++;
7579  }
7580 
7581  return SCIP_OKAY;
7582  }
7583 
7584  /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7585  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7586  rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7587 
7588  if( (*cutoff) )
7589  {
7590  /* note that cutoff may occur if presolving has not been executed fully */
7591  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7592 
7593  if( tightened )
7594  {
7595  (*success) =TRUE;
7596  (*nfixedvars)++;
7597  }
7598 
7599  return SCIP_OKAY;
7600  }
7601 
7602  return SCIP_OKAY;
7603 }
7604 
7605 /** is it possible, to round variable down w.r.t. objective function */
7606 static
7608  SCIP* scip, /**< SCIP data structure */
7609  SCIP_VAR* var, /**< problem variable */
7610  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7611  )
7612 {
7613  SCIP_Real objval;
7614  int scalar;
7615 
7616  assert(roundable != NULL);
7617 
7618  *roundable = TRUE;
7619 
7620  /* a fixed variable can be definition always be safely rounded */
7622  return SCIP_OKAY;
7623 
7624  /* in case the variable is not active we need to check the object coefficient of the active variable */
7625  if( !SCIPvarIsActive(var) )
7626  {
7627  SCIP_VAR* actvar;
7628  int constant;
7629 
7630  actvar = var;
7631 
7632  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7633  assert(scalar != 0);
7634 
7635  objval = scalar * SCIPvarGetObj(actvar);
7636  }
7637  else
7638  {
7639  scalar = 1;
7640  objval = SCIPvarGetObj(var);
7641  }
7642 
7643  /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7644  * (the transformed problem is always a minimization problem)
7645  *
7646  * @note that we need to check this condition w.r.t. active variable space
7647  */
7648  if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7649  *roundable = FALSE;
7650 
7651  return SCIP_OKAY;
7652 }
7653 
7654 /** is it possible, to round variable up w.r.t. objective function */
7655 static
7657  SCIP* scip, /**< SCIP data structure */
7658  SCIP_VAR* var, /**< problem variable */
7659  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7660  )
7661 {
7662  SCIP_Real objval;
7663  int scalar;
7664 
7665  assert(roundable != NULL);
7666 
7667  *roundable = TRUE;
7668 
7669  /* a fixed variable can be definition always be safely rounded */
7671  return SCIP_OKAY;
7672 
7673  /* in case the variable is not active we need to check the object coefficient of the active variable */
7674  if( !SCIPvarIsActive(var) )
7675  {
7676  SCIP_VAR* actvar;
7677  int constant;
7678 
7679  actvar = var;
7680 
7681  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7682  assert(scalar != 0);
7683 
7684  objval = scalar * SCIPvarGetObj(actvar);
7685  }
7686  else
7687  {
7688  scalar = 1;
7689  objval = SCIPvarGetObj(var);
7690  }
7691 
7692  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7693  * (the transformed problem is always a minimization problem)
7694  *
7695  * @note that we need to check this condition w.r.t. active variable space
7696  */
7697  if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7698  *roundable = FALSE;
7699 
7700  return SCIP_OKAY;
7701 }
7702 
7703 /** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7704  * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7705  * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7706  * the only one locking this variable in the corresponding direction.
7707  */
7708 static
7710  SCIP* scip, /**< SCIP data structure */
7711  SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7712  int nconss, /**< number of cumulative constraints */
7713  SCIP_Bool local, /**< use local bounds effective horizon? */
7714  int* alternativelbs, /**< alternative lower bounds */
7715  int* alternativeubs, /**< alternative lower bounds */
7716  int* downlocks, /**< number of constraints with down lock participating by the computation */
7717  int* uplocks /**< number of constraints with up lock participating by the computation */
7718  )
7719 {
7720  int nvars;
7721  int c;
7722  int v;
7723 
7724  for( c = 0; c < nconss; ++c )
7725  {
7726  SCIP_CONSDATA* consdata;
7727  SCIP_CONS* cons;
7728  SCIP_VAR* var;
7729  int hmin;
7730  int hmax;
7731 
7732  cons = conss[c];
7733  assert(cons != NULL);
7734 
7735  /* ignore constraints which are already deletet and those which are not check constraints */
7736  if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7737  continue;
7738 
7739  consdata = SCIPconsGetData(cons);
7740  assert(consdata != NULL);
7741  assert(consdata->nvars > 1);
7742 
7743  /* compute the hmin and hmax */
7744  if( local )
7745  {
7746  SCIP_PROFILE* profile;
7747 
7748  SCIP_RETCODE retcode = SCIP_OKAY;
7749 
7750  /* create empty resource profile with infinity resource capacity */
7751  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7752 
7753  /* create worst case resource profile */
7754  retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
7755 
7756  hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7757  hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7758 
7759  /* free worst case profile */
7760  SCIPprofileFree(&profile);
7761 
7762  if( retcode != SCIP_OKAY )
7763  return retcode;
7764  }
7765  else
7766  {
7767  hmin = consdata->hmin;
7768  hmax = consdata->hmax;
7769  }
7770 
7771  consdata = SCIPconsGetData(cons);
7772  assert(consdata != NULL);
7773 
7774  nvars = consdata->nvars;
7775 
7776  for( v = 0; v < nvars; ++v )
7777  {
7778  int scalar;
7779  int constant;
7780  int idx;
7781 
7782  var = consdata->vars[v];
7783  assert(var != NULL);
7784 
7785  /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7786  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR);
7787 
7788  /* ignore variable locally fixed variables */
7789  if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7790  continue;
7791 
7792 
7793  SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7794  idx = SCIPvarGetProbindex(var);
7795  assert(idx >= 0);
7796 
7797  /* first check lower bound fixing */
7798  if( consdata->downlocks[v] )
7799  {
7800  int ect;
7801  int est;
7802 
7803  /* the variable has a down locked */
7804  est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7805  ect = est + consdata->durations[v];
7806 
7807  if( ect <= hmin || hmin >= hmax )
7808  downlocks[idx]++;
7809  else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7810  {
7811  alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7812  downlocks[idx]++;
7813  }
7814  }
7815 
7816  /* second check upper bound fixing */
7817  if( consdata->uplocks[v] )
7818  {
7819  int duration;
7820  int lct;
7821  int lst;
7822 
7823  duration = consdata->durations[v];
7824 
7825  /* the variable has a up lock locked */
7826  lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7827  lct = lst + duration;
7828 
7829  if( lst >= hmax || hmin >= hmax )
7830  uplocks[idx]++;
7831  else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7832  {
7833  alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7834  uplocks[idx]++;
7835  }
7836  }
7837  }
7838  }
7839 
7840  return SCIP_OKAY;
7841 }
7842 
7843 /** apply all fixings which are given by the alternative bounds */
7844 static
7846  SCIP* scip, /**< SCIP data structure */
7847  SCIP_VAR** vars, /**< array of active variables */
7848  int nvars, /**< number of active variables */
7849  int* alternativelbs, /**< alternative lower bounds */
7850  int* alternativeubs, /**< alternative lower bounds */
7851  int* downlocks, /**< number of constraints with down lock participating by the computation */
7852  int* uplocks, /**< number of constraints with up lock participating by the computation */
7853  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7854  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7855  )
7856 {
7857  SCIP_Real* downimpllbs;
7858  SCIP_Real* downimplubs;
7859  SCIP_Real* downproplbs;
7860  SCIP_Real* downpropubs;
7861  SCIP_Real* upimpllbs;
7862  SCIP_Real* upimplubs;
7863  SCIP_Real* upproplbs;
7864  SCIP_Real* uppropubs;
7865  int v;
7866 
7867  /* get temporary memory for storing probing results */
7868  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7869  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7870  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7871  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7872  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7873  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7874  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7875  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7876 
7877  for( v = 0; v < nvars; ++v )
7878  {
7879  SCIP_VAR* var;
7880  SCIP_Bool infeasible;
7881  SCIP_Bool fixed;
7882  SCIP_Bool roundable;
7883  int ub;
7884  int lb;
7885 
7886  var = vars[v];
7887  assert(var != NULL);
7888 
7889  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7890  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7891 
7892  /* ignore fixed variables */
7893  if( ub - lb <= 0 )
7894  continue;
7895 
7896 
7897  if( SCIPvarGetNLocksDown(var) == downlocks[v] )
7898  {
7899  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7900 
7901  if( roundable )
7902  {
7903  if( alternativelbs[v] > ub )
7904  {
7905  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7906  assert(!infeasible);
7907  assert(fixed);
7908 
7909  (*nfixedvars)++;
7910 
7911  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7912  * constraints
7913  */
7914  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7915  }
7916  else
7917  {
7918  SCIP_Bool success;
7919 
7920  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7921  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7922  * infeasible we can apply the dual reduction; otherwise we do nothing
7923  */
7924  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7925  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7926  nfixedvars, &success, cutoff) );
7927 
7928  if( success )
7929  {
7930  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7931  }
7932 
7933  }
7934  }
7935  }
7936 
7937  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7938  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7939 
7940  /* ignore fixed variables */
7941  if( ub - lb <= 0 )
7942  continue;
7943 
7944  if( SCIPvarGetNLocksUp(var) == uplocks[v] )
7945  {
7946  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7947 
7948  if( roundable )
7949  {
7950  if( alternativeubs[v] < lb )
7951  {
7952  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
7953  assert(!infeasible);
7954  assert(fixed);
7955 
7956  (*nfixedvars)++;
7957 
7958  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7959  * constraints
7960  */
7961  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7962  }
7963  else
7964  {
7965  SCIP_Bool success;
7966 
7967  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7968  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7969  * infeasible we can apply the dual reduction; otherwise we do nothing
7970  */
7971  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
7972  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7973  nfixedvars, &success, cutoff) );
7974 
7975  if( success )
7976  {
7977  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7978  }
7979  }
7980  }
7981  }
7982  }
7983 
7984  /* free temporary memory */
7985  SCIPfreeBufferArray(scip, &uppropubs);
7986  SCIPfreeBufferArray(scip, &upproplbs);
7987  SCIPfreeBufferArray(scip, &upimplubs);
7988  SCIPfreeBufferArray(scip, &upimpllbs);
7989  SCIPfreeBufferArray(scip, &downpropubs);
7990  SCIPfreeBufferArray(scip, &downproplbs);
7991  SCIPfreeBufferArray(scip, &downimplubs);
7992  SCIPfreeBufferArray(scip, &downimpllbs);
7993 
7994  return SCIP_OKAY;
7995 }
7996 
7997 /** propagate all constraints together */
7998 static
8000  SCIP* scip, /**< SCIP data structure */
8001  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
8002  SCIP_CONS** conss, /**< all cumulative constraint */
8003  int nconss, /**< number of cumulative constraints */
8004  SCIP_Bool local, /**< use local bounds effective horizon? */
8005  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
8006  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
8007  SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
8008  )
8009 { /*lint --e{715}*/
8010  SCIP_VAR** vars;
8011  int* downlocks;
8012  int* uplocks;
8013  int* alternativelbs;
8014  int* alternativeubs;
8015  int oldnfixedvars;
8016  int nvars;
8017  int v;
8018 
8019  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
8020  return SCIP_OKAY;
8021 
8022  nvars = SCIPgetNVars(scip);
8023  oldnfixedvars = *nfixedvars;
8024 
8025  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
8026  SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
8027  SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
8028  SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
8029  SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
8030 
8031  /* initialize arrays */
8032  for( v = 0; v < nvars; ++v )
8033  {
8034  downlocks[v] = 0;
8035  uplocks[v] = 0;
8036  alternativelbs[v] = INT_MAX;
8037  alternativeubs[v] = INT_MIN;
8038  }
8039 
8040  /* compute alternative bounds */
8041  SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
8042 
8043  /* apply fixing which result of the alternative bounds directly */
8044  SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
8045  nfixedvars, cutoff) );
8046 
8047  if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
8048  {
8049  SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
8050  }
8051 
8052  /* free all buffers */
8053  SCIPfreeBufferArray(scip, &alternativeubs);
8054  SCIPfreeBufferArray(scip, &alternativelbs);
8055  SCIPfreeBufferArray(scip, &uplocks);
8056  SCIPfreeBufferArray(scip, &downlocks);
8057  SCIPfreeBufferArray(scip, &vars);
8058 
8059  return SCIP_OKAY;
8060 }
8061 
8062 /**@} */
8063 
8064 /**@name Linear relaxations
8065  *
8066  * @{
8067  */
8068 
8069 /** creates covering cuts for jobs violating resource constraints */
8070 static
8072  SCIP* scip, /**< SCIP data structure */
8073  SCIP_CONS* cons, /**< constraint to be checked */
8074  int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8075  int time /**< at this point in time covering constraints are valid */
8076  )
8077 {
8078  SCIP_CONSDATA* consdata;
8079  SCIP_ROW* row;
8080  int* flexibleids;
8081  int* demands;
8082 
8083  char rowname[SCIP_MAXSTRLEN];
8084 
8085  int remainingcap;
8086  int smallcoversize; /* size of a small cover */
8087  int bigcoversize; /* size of a big cover */
8088  int nvars;
8089 
8090  int nflexible;
8091  int sumdemand; /* demand of all jobs up to a certain index */
8092  int j;
8093 
8094  assert(cons != NULL);
8095 
8096  /* get constraint data structure */
8097  consdata = SCIPconsGetData(cons);
8098  assert(consdata != NULL );
8099 
8100  nvars = consdata->nvars;
8101 
8102  /* sort jobs according to demands */
8103  SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8104  SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8105 
8106  nflexible = 0;
8107  remainingcap = consdata->capacity;
8108 
8109  /* get all jobs intersecting point 'time' with their bounds */
8110  for( j = 0; j < nvars; ++j )
8111  {
8112  int ub;
8113 
8114  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8115 
8116  /* only add jobs to array if they intersect with point 'time' */
8117  if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8118  {
8119  /* if job is fixed, capacity has to be decreased */
8120  if( startvalues[j] == ub )
8121  {
8122  remainingcap -= consdata->demands[j];
8123  }
8124  else
8125  {
8126  demands[nflexible] = consdata->demands[j];
8127  flexibleids[nflexible] = j;
8128  ++nflexible;
8129  }
8130  }
8131  }
8132  assert(remainingcap >= 0);
8133 
8134  /* sort demands and job ids */
8135  SCIPsortIntInt(demands, flexibleids, nflexible);
8136 
8137  /*
8138  * version 1:
8139  * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8140  * erzeuge cover constraint
8141  *
8142  */
8143 
8144  /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8145  sumdemand = 0;
8146  j = 0;
8147 
8148  while( j < nflexible && sumdemand <= remainingcap )
8149  {
8150  sumdemand += demands[j];
8151  j++;
8152  }
8153 
8154  /* j jobs form a conflict, set coversize to 'j - 1' */
8155  bigcoversize = j-1;
8156  assert(sumdemand > remainingcap);
8157  assert(bigcoversize < nflexible);
8158 
8159  /* - create a row for all jobs and their binary variables.
8160  * - at most coversize many binary variables of jobs can be set to one
8161  */
8162 
8163  /* construct row name */
8164  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8165  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8166  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8167  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8168 
8169  for( j = 0; j < nflexible; ++j )
8170  {
8171  SCIP_VAR** binvars;
8172  int* vals;
8173  int nbinvars;
8174  int idx;
8175  int start;
8176  int end;
8177  int lb;
8178  int ub;
8179  int b;
8180 
8181  idx = flexibleids[j];
8182 
8183  /* get and add binvars into var array */
8184  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8185  assert(nbinvars != 0);
8186 
8187  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8188  assert(vals != NULL);
8189 
8190  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8191  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8192 
8193  /* compute start and finishing time */
8194  start = time - consdata->durations[idx] + 1;
8195  end = MIN(time, ub);
8196 
8197  /* add all neccessary binary variables */
8198  for( b = 0; b < nbinvars; ++b )
8199  {
8200  if( vals[b] < start || vals[b] < lb )
8201  continue;
8202 
8203  if( vals[b] > end )
8204  break;
8205 
8206  assert(binvars[b] != NULL);
8207  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8208  }
8209  }
8210 
8211  /* insert and release row */
8212  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8213 
8214  if( consdata->bcoverrowssize == 0 )
8215  {
8216  consdata->bcoverrowssize = 10;
8217  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8218  }
8219  if( consdata->nbcoverrows == consdata->bcoverrowssize )
8220  {
8221  consdata->bcoverrowssize *= 2;
8222  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8223  }
8224 
8225  consdata->bcoverrows[consdata->nbcoverrows] = row;
8226  consdata->nbcoverrows++;
8227 
8228  /*
8229  * version 2:
8230  * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8231  * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8232  */
8233  /* find maximum number of jobs that can run in parallel (= coversize -1) */
8234  sumdemand = 0;
8235  j = nflexible -1;
8236  while( sumdemand <= remainingcap )
8237  {
8238  assert(j >= 0);
8239  sumdemand += demands[j];
8240  j--;
8241  }
8242 
8243  smallcoversize = nflexible - (j + 1) - 1;
8244  while( j > 0 && demands[j] == demands[nflexible-1] )
8245  --j;
8246 
8247  assert(smallcoversize < nflexible);
8248 
8249  if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8250  {
8251  /* construct row name */
8252  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8253  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8254  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8255  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8256 
8257  /* filter binary variables for each unfixed job */
8258  for( j = j + 1; j < nflexible; ++j )
8259  {
8260  SCIP_VAR** binvars;
8261  int* vals;
8262  int nbinvars;
8263  int idx;
8264  int start;
8265  int end;
8266  int lb;
8267  int ub;
8268  int b;
8269 
8270  idx = flexibleids[j];
8271 
8272  /* get and add binvars into var array */
8273  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8274  assert(nbinvars != 0);
8275 
8276  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8277  assert(vals != NULL);
8278 
8279  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8280  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8281 
8282  /* compute start and finishing time */
8283  start = time - consdata->durations[idx] + 1;
8284  end = MIN(time, ub);
8285 
8286  /* add all neccessary binary variables */
8287  for( b = 0; b < nbinvars; ++b )
8288  {
8289  if( vals[b] < start || vals[b] < lb )
8290  continue;
8291 
8292  if( vals[b] > end )
8293  break;
8294 
8295  assert(binvars[b] != NULL);
8296  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8297  }
8298  }
8299 
8300  /* insert and release row */
8301  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8302  if( consdata->scoverrowssize == 0 )
8303  {
8304  consdata->scoverrowssize = 10;
8305  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8306  }
8307  if( consdata->nscoverrows == consdata->scoverrowssize )
8308  {
8309  consdata->scoverrowssize *= 2;
8310  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8311  }
8312 
8313  consdata->scoverrows[consdata->nscoverrows] = row;
8314  consdata->nscoverrows++;
8315  }
8316 
8317  /* free buffer arrays */
8318  SCIPfreeBufferArray(scip, &flexibleids);
8319  SCIPfreeBufferArray(scip, &demands);
8320 
8321  return SCIP_OKAY;
8322 }
8323 
8324 /** method to construct cover cuts for all points in time */
8325 static
8327  SCIP* scip, /**< SCIP data structure */
8328  SCIP_CONS* cons /**< constraint to be separated */
8329  )
8330 {
8331  SCIP_CONSDATA* consdata;
8332 
8333  int* startvalues; /* stores when each job is starting */
8334  int* endvalues; /* stores when each job ends */
8335  int* startvaluessorted; /* stores when each job is starting */
8336  int* endvaluessorted; /* stores when each job ends */
8337  int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8338  int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8339 
8340  int nvars; /* number of jobs for this constraint */
8341  int freecapacity; /* remaining capacity */
8342  int curtime; /* point in time which we are just checking */
8343  int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8344 
8345  int hmin;
8346  int hmax;
8347 
8348  int j;
8349  int t;
8350 
8351  assert(scip != NULL);
8352  assert(cons != NULL);
8353 
8354  consdata = SCIPconsGetData(cons);
8355  assert(consdata != NULL);
8356 
8357  /* if no activities are associated with this resource then this constraint is redundant */
8358  if( consdata->vars == NULL )
8359  return SCIP_OKAY;
8360 
8361  nvars = consdata->nvars;
8362  hmin = consdata->hmin;
8363  hmax = consdata->hmax;
8364 
8365  SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8366  SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8367  SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8368  SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8369  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8370  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8371 
8372  /* assign start and endpoints to arrays */
8373  for ( j = 0; j < nvars; ++j )
8374  {
8375  startvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8376  startvaluessorted[j] = startvalues[j];
8377 
8378  endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8379  endvaluessorted[j] = endvalues[j];
8380 
8381  startindices[j] = j;
8382  endindices[j] = j;
8383  }
8384 
8385  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8386  * (and sort the indices in the same way) */
8387  SCIPsortIntInt(startvaluessorted, startindices, nvars);
8388  SCIPsortIntInt(endvaluessorted, endindices, nvars);
8389 
8390  endidx = 0;
8391  freecapacity = consdata->capacity;
8392 
8393  /* check each startpoint of a job whether the capacity is kept or not */
8394  for( j = 0; j < nvars; ++j )
8395  {
8396  curtime = startvaluessorted[j];
8397  if( curtime >= hmax )
8398  break;
8399 
8400  /* subtract all capacity needed up to this point */
8401  freecapacity -= consdata->demands[startindices[j]];
8402 
8403  while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8404  {
8405  ++j;
8406  freecapacity -= consdata->demands[startindices[j]];
8407  }
8408 
8409  /* free all capacity usages of jobs the are no longer running */
8410  while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8411  {
8412  freecapacity += consdata->demands[endindices[endidx]];
8413  ++endidx;
8414  }
8415 
8416  assert(freecapacity <= consdata->capacity);
8417  assert(endidx <= nvars);
8418 
8419  /* --> endindex - points to the next job which will finish
8420  * j - points to the last job that has been released
8421  */
8422 
8423 
8424  /* check freecapacity to be smaller than zero
8425  * then we will add cover constraints to the MIP
8426  */
8427  if( freecapacity < 0 && curtime >= hmin )
8428  {
8429  int nextprofilechange;
8430 
8431  /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8432  if( j < nvars-1 )
8433  nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8434  else
8435  nextprofilechange = endvaluessorted[endidx];
8436 
8437  nextprofilechange = MIN(nextprofilechange, hmax);
8438 
8439  for( t = curtime; t < nextprofilechange; ++t )
8440  {
8441  SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8442 
8443  /* create covering constraint */
8444  SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8445 
8446  }
8447  } /* end if freecapacity > 0 */
8448 
8449  } /*lint --e{850}*/
8450 
8451  consdata->covercuts = TRUE;
8452 
8453  /* free all buffer arrays */
8454  SCIPfreeBufferArray(scip, &endindices);
8455  SCIPfreeBufferArray(scip, &startindices);
8456  SCIPfreeBufferArray(scip, &endvaluessorted);
8457  SCIPfreeBufferArray(scip, &startvaluessorted);
8458  SCIPfreeBufferArray(scip, &endvalues);
8459  SCIPfreeBufferArray(scip, &startvalues);
8460 
8461  return SCIP_OKAY;
8462 }
8463 
8464 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8465  * constraint
8466  */
8467 static
8469  SCIP* scip, /**< SCIP data structure */
8470  SCIP_CONS* cons, /**< constraint to be checked */
8471  int* startindices, /**< permutation with rspect to the start times */
8472  int curtime, /**< current point in time */
8473  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8474  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8475  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8476  )
8477 {
8478  SCIP_CONSDATA* consdata;
8479  SCIP_VAR** binvars;
8480  int* coefs;
8481  int nbinvars;
8482  char name[SCIP_MAXSTRLEN];
8483  int capacity;
8484  int b;
8485 
8486  assert(nstarted > nfinished);
8487 
8488  consdata = SCIPconsGetData(cons);
8489  assert(consdata != NULL);
8490  assert(consdata->nvars > 0);
8491 
8492  capacity = consdata->capacity;
8493  assert(capacity > 0);
8494 
8495  nbinvars = 0;
8496  SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8497 
8498  /* construct row name */
8499  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8500 
8501  if( cutsasconss )
8502  {
8503  SCIP_CONS* lincons;
8504 
8505  /* create knapsack constraint for the given time point */
8506  SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8507  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) );
8508 
8509  for( b = 0; b < nbinvars; ++b )
8510  {
8511  SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8512  }
8513 
8514  /* add and release the new constraint */
8515  SCIP_CALL( SCIPaddCons(scip, lincons) );
8516  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8517  }
8518  else
8519  {
8520  SCIP_ROW* row;
8521 
8522  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8523  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8524 
8525  for( b = 0; b < nbinvars; ++b )
8526  {
8527  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8528  }
8529 
8530  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8531  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8532 
8533  if( consdata->demandrowssize == 0 )
8534  {
8535  consdata->demandrowssize = 10;
8536  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8537  }
8538  if( consdata->ndemandrows == consdata->demandrowssize )
8539  {
8540  consdata->demandrowssize *= 2;
8541  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8542  }
8543 
8544  consdata->demandrows[consdata->ndemandrows] = row;
8545  consdata->ndemandrows++;
8546  }
8547 
8548  SCIPfreeBufferArrayNull(scip, &binvars);
8549  SCIPfreeBufferArrayNull(scip, &coefs);
8550 
8551  return SCIP_OKAY;
8552 }
8553 
8554 /** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8555  * row
8556  */
8557 static
8559  SCIP* scip, /**< SCIP data structure */
8560  SCIP_CONS* cons, /**< constraint to be checked */
8561  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8562  )
8563 {
8564  SCIP_CONSDATA* consdata;
8565 
8566  int* starttimes; /* stores when each job is starting */
8567  int* endtimes; /* stores when each job ends */
8568  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8569  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8570 
8571  int nvars; /* number of activities for this constraint */
8572  int freecapacity; /* remaining capacity */
8573  int curtime; /* point in time which we are just checking */
8574  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8575 
8576  int hmin;
8577  int hmax;
8578 
8579  int j;
8580 
8581  assert(scip != NULL);
8582  assert(cons != NULL);
8583 
8584  consdata = SCIPconsGetData(cons);
8585  assert(consdata != NULL);
8586 
8587  nvars = consdata->nvars;
8588 
8589  /* if no activities are associated with this cumulative then this constraint is redundant */
8590  if( nvars == 0 )
8591  return SCIP_OKAY;
8592 
8593  assert(consdata->vars != NULL);
8594 
8595  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8596  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8597  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8598  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8599 
8600  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8601  SCIPconsGetName(cons), nvars);
8602 
8603  /* create event point arrays */
8604  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8605  starttimes, endtimes, startindices, endindices, FALSE);
8606 
8607  endindex = 0;
8608  freecapacity = consdata->capacity;
8609  hmin = consdata->hmin;
8610  hmax = consdata->hmax;
8611 
8612  /* check each startpoint of a job whether the capacity is kept or not */
8613  for( j = 0; j < nvars; ++j )
8614  {
8615  curtime = starttimes[j];
8616  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8617 
8618  if( curtime >= hmax )
8619  break;
8620 
8621  /* remove the capacity requirments for all job which start at the curtime */
8622  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8623 
8624  /* add the capacity requirments for all job which end at the curtime */
8625  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8626 
8627  assert(freecapacity <= consdata->capacity);
8628  assert(endindex <= nvars);
8629 
8630  /* endindex - points to the next job which will finish */
8631  /* j - points to the last job that has been released */
8632 
8633  /* if free capacity is smaller than zero, then add rows to the LP */
8634  if( freecapacity < 0 && curtime >= hmin )
8635  {
8636  int nextstarttime;
8637  int t;
8638 
8639  /* step forward until next job is released and see whether capacity constraint is met or not */
8640  if( j < nvars-1 )
8641  nextstarttime = starttimes[j+1];
8642  else
8643  nextstarttime = endtimes[nvars-1];
8644 
8645  nextstarttime = MIN(nextstarttime, hmax);
8646 
8647  /* create capacity restriction row for current event point */
8648  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8649 
8650  /* create for all points in time between the current event point and next start event point a row if the free
8651  * capacity is still smaller than zero */
8652  for( t = curtime+1 ; t < nextstarttime; ++t )
8653  {
8654  /* add the capacity requirments for all job which end at the curtime */
8655  addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8656 
8657  if( freecapacity < 0 )
8658  {
8659  /* add constraint */
8660  SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8661 
8662  /* create capacity restriction row */
8663  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8664  }
8665  else
8666  break;
8667  }
8668  }
8669  } /*lint --e{850}*/
8670 
8671  /* free all buffer arrays */
8672  SCIPfreeBufferArray(scip, &endindices);
8673  SCIPfreeBufferArray(scip, &startindices);
8674  SCIPfreeBufferArray(scip, &endtimes);
8675  SCIPfreeBufferArray(scip, &starttimes);
8676 
8677  return SCIP_OKAY;
8678 }
8679 
8680 /** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8681  * capacity is larger than the capacity of the cumulative constraint
8682  * - for each necessary point in time:
8683  *
8684  * sum_j sum_t demand_j * x_{j,t} <= capacity
8685  *
8686  * where x(j,t) is the binary variables of job j at time t
8687  */
8688 static
8690  SCIP* scip, /**< SCIP data structure */
8691  SCIP_CONS* cons, /**< cumulative constraint */
8692  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8693  )
8694 {
8695  SCIP_CONSDATA* consdata;
8696 
8697  consdata = SCIPconsGetData(cons);
8698  assert(consdata != NULL);
8699  assert(consdata->demandrows == NULL);
8700  assert(consdata->ndemandrows == 0);
8701 
8702  /* collect the linking constraints */
8703  if( consdata->linkingconss == NULL )
8704  {
8705  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8706  }
8707 
8708  SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8709 
8710  /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8711  if( cutsasconss )
8712  {
8713  if( SCIPconsIsInitial(cons) )
8714  {
8715  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
8716  }
8717  if( SCIPconsIsSeparated(cons) )
8718  {
8719  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
8720  }
8721  if( SCIPconsIsEnforced(cons) )
8722  {
8723  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
8724  }
8725  }
8726 
8727  return SCIP_OKAY;
8728 }
8729 
8730 /** adds linear relaxation of cumulative constraint to the LP */
8731 static
8733  SCIP* scip, /**< SCIP data structure */
8734  SCIP_CONS* cons, /**< cumulative constraint */
8735  SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
8736  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
8737  )
8738 {
8739  SCIP_CONSDATA* consdata;
8740  int r;
8741 
8742  consdata = SCIPconsGetData(cons);
8743  assert(consdata != NULL);
8744 
8745  if( consdata->demandrows == NULL )
8746  {
8747  SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8748  }
8749  assert(consdata->ndemandrows == 0 || consdata->demandrows != NULL);
8750 
8751  for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8752  {
8753  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8754  {
8755  assert(consdata->demandrows[r] != NULL);
8756  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
8757  }
8758  }
8759 
8760  return SCIP_OKAY;
8761 }
8762 
8763 /** checks constraint for violation, and adds it as a cut if possible */
8764 static
8766  SCIP* scip, /**< SCIP data structure */
8767  SCIP_CONS* cons, /**< cumulative constraint to be separated */
8768  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8769  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8770  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8771  )
8772 { /*lint --e{715}*/
8773  SCIP_CONSDATA* consdata;
8774  int ncuts;
8775  int r;
8776 
8777  assert(scip != NULL);
8778  assert(cons != NULL);
8779  assert(separated != NULL);
8780  assert(cutoff != NULL);
8781 
8782  *separated = FALSE;
8783  *cutoff = FALSE;
8784 
8785  consdata = SCIPconsGetData(cons);
8786  assert(consdata != NULL);
8787 
8788  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8789 
8790  if( consdata->demandrows == NULL )
8791  {
8792  SCIP_CALL( createRelaxation(scip, cons, FALSE) );
8793  }
8794  assert(consdata->ndemandrows == 0 || consdata->demandrows != NULL);
8795 
8796  ncuts = 0;
8797 
8798  /* check each row that is not contained in LP */
8799  for( r = 0; r < consdata->ndemandrows; ++r )
8800  {
8801  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8802  {
8803  SCIP_Real feasibility;
8804 
8805  if( sol != NULL )
8806  feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8807  else
8808  feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8809 
8810  if( SCIPisFeasNegative(scip, feasibility) )
8811  {
8812  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
8813  if ( *cutoff )
8814  {
8815  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8816  return SCIP_OKAY;
8817  }
8818  *separated = TRUE;
8819  ncuts++;
8820  }
8821  }
8822  }
8823 
8824  if( ncuts > 0 )
8825  {
8826  SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8827 
8828  /* if successful, reset age of constraint */
8829  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8830  (*separated) = TRUE;
8831  }
8832 
8833  return SCIP_OKAY;
8834 }
8835 
8836 /** checks constraint for violation, and adds it as a cut if possible */
8837 static
8839  SCIP* scip, /**< SCIP data structure */
8840  SCIP_CONS* cons, /**< logic or constraint to be separated */
8841  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8842  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8843  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8844  )
8845 {
8846  SCIP_CONSDATA* consdata;
8847  SCIP_ROW* row;
8848  SCIP_Real minfeasibility;
8849  int r;
8850 
8851  assert(scip != NULL);
8852  assert(cons != NULL);
8853  assert(separated != NULL);
8854  assert(cutoff != NULL);
8855 
8856  *separated = FALSE;
8857  *cutoff = FALSE;
8858 
8859  consdata = SCIPconsGetData(cons);
8860  assert(consdata != NULL);
8861 
8862  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8863 
8864  /* collect the linking constraints */
8865  if( consdata->linkingconss == NULL )
8866  {
8867  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8868  }
8869 
8870  if( !consdata->covercuts )
8871  {
8872  SCIP_CALL( createCoverCuts(scip, cons) );
8873  }
8874 
8875  row = NULL;
8876  minfeasibility = SCIPinfinity(scip);
8877 
8878  /* check each row of small covers that is not contained in LP */
8879  for( r = 0; r < consdata->nscoverrows; ++r )
8880  {
8881  if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8882  {
8883  SCIP_Real feasibility;
8884 
8885  assert(consdata->scoverrows[r] != NULL);
8886  if( sol != NULL )
8887  feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8888  else
8889  feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8890 
8891  if( minfeasibility > feasibility )
8892  {
8893  minfeasibility = feasibility;
8894  row = consdata->scoverrows[r];
8895  }
8896  }
8897  }
8898 
8899  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8900 
8901  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8902  {
8903  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8904  SCIPconsGetName(cons), minfeasibility);
8905 
8906  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8907  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8908  if ( *cutoff )
8909  return SCIP_OKAY;
8910  (*separated) = TRUE;
8911  }
8912 
8913  minfeasibility = SCIPinfinity(scip);
8914  row = NULL;
8915 
8916  /* check each row of small covers that is not contained in LP */
8917  for( r = 0; r < consdata->nbcoverrows; ++r )
8918  {
8919  if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8920  {
8921  SCIP_Real feasibility;
8922 
8923  assert(consdata->bcoverrows[r] != NULL);
8924  if( sol != NULL )
8925  feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8926  else
8927  feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8928 
8929  if( minfeasibility > feasibility )
8930  {
8931  minfeasibility = feasibility;
8932  row = consdata->bcoverrows[r];
8933  }
8934  }
8935  }
8936 
8937  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8938 
8939  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8940  {
8941  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8942  SCIPconsGetName(cons), minfeasibility);
8943 
8944  assert(row != NULL);
8945  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8946  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8947  if ( *cutoff )
8948  return SCIP_OKAY;
8949  (*separated) = TRUE;
8950  }
8951 
8952  return SCIP_OKAY;
8953 }
8954 
8955 /** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
8956 static
8958  SCIP* scip, /**< SCIP data structure */
8959  SCIP_CONS* cons, /**< constraint to be checked */
8960  int* startindices, /**< permutation with rspect to the start times */
8961  int curtime, /**< current point in time */
8962  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8963  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8964  SCIP_Bool lower /**< shall cuts be created due to lower or upper bounds? */
8965  )
8966 {
8967  SCIP_CONSDATA* consdata;
8968  char name[SCIP_MAXSTRLEN];
8969  SCIP_Bool infeasible;
8970  int lhs; /* left hand side of constraint */
8971 
8972  SCIP_VAR** activevars;
8973  SCIP_ROW* row;
8974 
8975  int v;
8976 
8977  assert(nstarted > nfinished);
8978 
8979  consdata = SCIPconsGetData(cons);
8980  assert(consdata != NULL);
8981  assert(consdata->nvars > 0);
8982 
8983 
8984  SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
8985 
8986  SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
8987 
8988  if( lower )
8989  {
8990  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
8991 
8992  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, (SCIP_Real) lhs, SCIPinfinity(scip),
8993  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8994  }
8995  else
8996  {
8997  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
8998  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real) lhs,
8999  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9000  }
9001 
9002  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
9003 
9004  for( v = 0; v < nstarted - nfinished; ++v )
9005  {
9006  SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
9007  }
9008 
9009  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
9010  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
9011 
9012  SCIP_CALL( SCIPaddRow(scip, row, TRUE, &infeasible) );
9013  assert( ! infeasible );
9014 
9015  SCIP_CALL( SCIPreleaseRow(scip, &row) );
9016 
9017  /* free buffers */
9018  SCIPfreeBufferArrayNull(scip, &activevars);
9019 
9020  return SCIP_OKAY;
9021 }
9022 
9023 /** checks constraint for violation, and adds it as a cut if possible */
9024 static
9026  SCIP* scip, /**< SCIP data structure */
9027  SCIP_CONS* cons, /**< cumulative constraint to be separated */
9028  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
9029  SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
9030  SCIP_Bool* separated /**< pointer to store TRUE, if a cut was found */
9031  )
9032 {
9033 
9034  SCIP_CONSDATA* consdata;
9035 
9036  int* starttimes; /* stores when each job is starting */
9037  int* endtimes; /* stores when each job ends */
9038  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
9039  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
9040 
9041  int nvars; /* number of activities for this constraint */
9042  int freecapacity; /* remaining capacity */
9043  int curtime; /* point in time which we are just checking */
9044  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
9045 
9046  int hmin;
9047  int hmax;
9048  int j;
9049 
9050  assert(scip != NULL);
9051  assert(cons != NULL);
9052 
9053  consdata = SCIPconsGetData(cons);
9054  assert(consdata != NULL);
9055 
9056  nvars = consdata->nvars;
9057 
9058  /* if no activities are associated with this cumulative then this constraint is redundant */
9059  if( nvars <= 1 )
9060  return SCIP_OKAY;
9061 
9062  assert(consdata->vars != NULL);
9063 
9064  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
9065  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
9066  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9067  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9068 
9069  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9070  SCIPconsGetName(cons), nvars);
9071 
9072  /* create event point arrays */
9073  createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9074 
9075  /* now nvars might be smaller than before! */
9076 
9077  endindex = 0;
9078  freecapacity = consdata->capacity;
9079  hmin = consdata->hmin;
9080  hmax = consdata->hmax;
9081 
9082  /* check each startpoint of a job whether the capacity is kept or not */
9083  for( j = 0; j < nvars; ++j )
9084  {
9085  curtime = starttimes[j];
9086 
9087  if( curtime >= hmax )
9088  break;
9089 
9090  /* remove the capacity requirements for all job which start at the curtime */
9091  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9092 
9093  /* add the capacity requirments for all job which end at the curtime */
9094  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9095 
9096  assert(freecapacity <= consdata->capacity);
9097  assert(endindex <= nvars);
9098 
9099  /* endindex - points to the next job which will finish */
9100  /* j - points to the last job that has been released */
9101 
9102  /* if free capacity is smaller than zero, then add rows to the LP */
9103  if( freecapacity < 0 && curtime >= hmin)
9104  {
9105  /* create capacity restriction row for current event point */
9106  SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower) );
9107  *separated = TRUE;
9108  }
9109  } /*lint --e{850}*/
9110 
9111  /* free all buffer arrays */
9112  SCIPfreeBufferArray(scip, &endindices);
9113  SCIPfreeBufferArray(scip, &startindices);
9114  SCIPfreeBufferArray(scip, &endtimes);
9115  SCIPfreeBufferArray(scip, &starttimes);
9116 
9117  return SCIP_OKAY;
9118 }
9119 
9120 /**@} */
9121 
9122 
9123 /**@name Presolving
9124  *
9125  * @{
9126  */
9127 
9128 #ifndef NDEBUG
9129 /** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9130  * correct
9131  */
9132 static
9134  SCIP* scip, /**< SCIP data structure */
9135  SCIP_CONS* cons /**< constraint to be checked */
9136  )
9137 {
9138  SCIP_CONSDATA* consdata;
9139  int capacity;
9140  int nvars;
9141  int j;
9142 
9143  assert(scip != NULL);
9144  assert(cons != NULL);
9145 
9146  consdata = SCIPconsGetData(cons);
9147  assert(consdata != NULL);
9148 
9149  nvars = consdata->nvars;
9150 
9151  /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9152  if( nvars <= 1 )
9153  return TRUE;
9154 
9155  assert(consdata->vars != NULL);
9156  capacity = consdata->capacity;
9157 
9158  /* check each activity: if demand is larger than capacity the problem is infeasible */
9159  for ( j = 0; j < nvars; ++j )
9160  {
9161  if( consdata->demands[j] > capacity )
9162  return FALSE;
9163  }
9164 
9165  return TRUE;
9166 }
9167 #endif
9168 
9169 /** delete constraint if it consists of at most one job
9170  *
9171  * @todo this method needs to be adjusted w.r.t. effective horizon
9172  */
9173 static
9175  SCIP* scip, /**< SCIP data structure */
9176  SCIP_CONS* cons, /**< constraint to propagate */
9177  int* ndelconss, /**< pointer to store the number of deleted constraints */
9178  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9179  )
9180 {
9181  SCIP_CONSDATA* consdata;
9182 
9183  assert(scip != NULL);
9184  assert(cons != NULL);
9185 
9186  consdata = SCIPconsGetData(cons);
9187  assert(consdata != NULL);
9188 
9189  if( consdata->nvars == 0 )
9190  {
9191  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9192 
9193  SCIP_CALL( SCIPdelCons(scip, cons) );
9194  (*ndelconss)++;
9195  }
9196  else if( consdata->nvars == 1 )
9197  {
9198  if( consdata->demands[0] > consdata->capacity )
9199  (*cutoff) = TRUE;
9200  else
9201  {
9202  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9203 
9204  SCIP_CALL( SCIPdelCons(scip, cons) );
9205  (*ndelconss)++;
9206  }
9207  }
9208 
9209  return SCIP_OKAY;
9210 }
9211 
9212 /** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9213  * this is done in the SCIP_DECL_CONSINITPRE() callback
9214  */
9215 static
9217  SCIP* scip, /**< SCIP data structure */
9218  SCIP_CONS* cons /**< constraint to propagate */
9219  )
9220 {
9221  SCIP_CONSDATA* consdata;
9222  SCIP_VAR* var;
9223  int demand;
9224  int duration;
9225  int hmin;
9226  int hmax;
9227  int est;
9228  int lct;
9229  int j;
9230 
9231  assert(scip != NULL);
9232  assert(cons != NULL);
9233 
9234  consdata = SCIPconsGetData(cons);
9235  assert(consdata != NULL);
9236 
9237  hmin = consdata->hmin;
9238  hmax = consdata->hmax;
9239 
9240  SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9241  SCIPconsGetName(cons), hmin, hmax);
9242 
9243  for( j = consdata->nvars-1; j >= 0; --j )
9244  {
9245  var = consdata->vars[j];
9246  demand = consdata->demands[j];
9247  duration = consdata->durations[j];
9248 
9249  /* earliest completion time (ect) and latest start time (lst) */
9250  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9251  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9252 
9253  if( demand == 0 || duration == 0 )
9254  {
9255  /* jobs with zero demand or zero duration can be removed */
9256  SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
9257  SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9258 
9259  /* remove variable form constraint */
9260  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9261  }
9262  else if( est >= hmax || lct <= hmin )
9263  {
9264  SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
9265  SCIPvarGetName(var), est, lct - duration, duration);
9266 
9267  /* delete variable at the given position */
9268  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9269 
9270  /* for the statistic we count the number of jobs which are irrelevant */
9271  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9272  }
9273  }
9274 
9275  return SCIP_OKAY;
9276 }
9277 
9278 /** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9279 static
9281  SCIP* scip, /**< SCIP data structure */
9282  SCIP_CONSDATA* consdata, /**< constraint data */
9283  int pos, /**< position of job in the consdata */
9284  int* nchgbds, /**< pointer to store the number of changed bounds */
9285  int* naddconss, /**< pointer to store the number of added constraints */
9286  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9287  )
9288 {
9289  SCIP_VAR* var;
9290  SCIP_Bool tightened;
9291  int duration;
9292  int ect;
9293  int lst;
9294 
9295  assert(scip != NULL);
9296 
9297  /* zero energy jobs should be removed already */
9298  assert(consdata->durations[pos] > 0);
9299  assert(consdata->demands[pos] > 0);
9300 
9301  var = consdata->vars[pos];
9302  assert(var != NULL);
9303  duration = consdata->durations[pos];
9304 
9305  /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9306  SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9307  SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9308 
9309  /* earliest completion time (ect) and latest start time (lst) */
9310  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9311  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9312 
9313  /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9314  if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9315  return SCIP_OKAY;
9316 
9317  if( ect > consdata->hmin && lst < consdata->hmax )
9318  {
9319  /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9320  *cutoff = TRUE;
9321  }
9322  else if( lst < consdata->hmax )
9323  {
9324  /* move the latest start time of this job in such a way that it finishes before or at hmin */
9325  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9326  assert(tightened);
9327  assert(!(*cutoff));
9328  (*nchgbds)++;
9329  }
9330  else if( ect > consdata->hmin )
9331  {
9332  /* move the earliest start time of this job in such a way that it starts after or at hmax */
9333  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9334  assert(tightened);
9335  assert(!(*cutoff));
9336  (*nchgbds)++;
9337  }
9338  else
9339  {
9340  /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9341  * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9342  *
9343  * (var <= hmin - duration) /\ (var >= hmax)
9344  */
9345  SCIP_CONS* cons;
9346 
9347  SCIP_VAR* vartuple[2];
9348  SCIP_BOUNDTYPE boundtypetuple[2];
9349  SCIP_Real boundtuple[2];
9350 
9351  char name[SCIP_MAXSTRLEN];
9352  int leftbound;
9353  int rightbound;
9354 
9355  leftbound = consdata->hmin - duration;
9356  rightbound = consdata->hmax;
9357 
9358  /* allocate temporary memory for arrays */
9359  vartuple[0] = var;
9360  vartuple[1] = var;
9361  boundtuple[0] = (SCIP_Real)leftbound;
9362  boundtuple[1] = (SCIP_Real)rightbound;
9363  boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9364  boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9365 
9366  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9367  SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9368 
9369  /* create and add bounddisjunction constraint */
9370  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9371  TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9372 
9373  SCIPdebugPrintCons(scip, cons, NULL);
9374 
9375  /* add and release the new constraint */
9376  SCIP_CALL( SCIPaddCons(scip, cons) );
9377  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9378  (*naddconss)++;
9379  }
9380 
9381  return SCIP_OKAY;
9382 }
9383 
9384 /** try to removed over sizeed jobs (the demand is larger than the capacity) */
9385 static
9387  SCIP* scip, /**< SCIP data structure */
9388  SCIP_CONS* cons, /**< constraint */
9389  int* nchgbds, /**< pointer to store the number of changed bounds */
9390  int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9391  int* naddconss, /**< pointer to store the number of added constraints */
9392  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9393  )
9394 {
9395  SCIP_CONSDATA* consdata;
9396  int capacity;
9397  int j;
9398 
9399  consdata = SCIPconsGetData(cons);
9400  assert(consdata != NULL);
9401 
9402  /* if a cutoff was already detected just return */
9403  if( *cutoff )
9404  return SCIP_OKAY;
9405 
9406  capacity = consdata->capacity;
9407 
9408  for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9409  {
9410  if( consdata->demands[j] > capacity )
9411  {
9412  SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9413 
9414  /* remove variable form constraint */
9415  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9416  (*nchgcoefs)++;
9417  }
9418  }
9419 
9420  SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9421 
9422  return SCIP_OKAY;
9423 }
9424 
9425 /** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9426 static
9428  SCIP* scip, /**< SCIP data structure */
9429  SCIP_VAR* var, /**< integer variable to fix */
9430  SCIP_Bool uplock, /**< has thet start time variable a up lock */
9431  int* nfixedvars /**< pointer to store the number fixed variables */
9432  )
9433 {
9434  SCIP_Bool infeasible;
9435  SCIP_Bool tightened;
9436  SCIP_Bool roundable;
9437 
9438  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9439  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9440  */
9441  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9442  return SCIP_OKAY;
9443 
9444  /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9445  * handler is the only one locking that variable up
9446  */
9447  assert(uplock == TRUE || uplock == FALSE);
9448  assert((int)TRUE == 1);
9449  assert((int)FALSE == 0);
9450 
9451  if( SCIPvarGetNLocksUp(var) > (int)(uplock) )
9452  return SCIP_OKAY;
9453 
9454  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9455 
9456  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9457  * (the transformed problem is always a minimization problem)
9458  */
9459  if( !roundable )
9460  return SCIP_OKAY;
9461 
9462  SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9464 
9465  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9466  assert(!infeasible);
9467 
9468  if( tightened )
9469  {
9470  SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9471  (*nfixedvars)++;
9472  }
9473 
9474  return SCIP_OKAY;
9475 }
9476 
9477 /** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9478 static
9480  SCIP* scip, /**< SCIP data structure */
9481  SCIP_VAR* var, /**< integer variable to fix */
9482  SCIP_Bool downlock, /**< has the variable a down lock */
9483  int* nfixedvars /**< pointer to store the number fixed variables */
9484  )
9485 {
9486  SCIP_Bool infeasible;
9487  SCIP_Bool tightened;
9488  SCIP_Bool roundable;
9489 
9490  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9491  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9492  */
9493  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9494  return SCIP_OKAY;
9495 
9496  /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9497  * handler is the only one locking that variable down
9498  */
9499  assert(downlock == TRUE || downlock == FALSE);
9500  assert((int)TRUE == 1);
9501  assert((int)FALSE == 0);
9502 
9503  if( SCIPvarGetNLocksDown(var) > (int)(downlock) )
9504  return SCIP_OKAY;
9505 
9506  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9507 
9508  /* is it possible, to round variable down w.r.t. objective function? */
9509  if( !roundable )
9510  return SCIP_OKAY;
9511 
9512  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9513  assert(!infeasible);
9514 
9515  if( tightened )
9516  {
9517  SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9518  (*nfixedvars)++;
9519  }
9520 
9521  return SCIP_OKAY;
9522 }
9523 
9524 /** normalize cumulative condition */
9525 static
9527  SCIP* scip, /**< SCIP data structure */
9528  int nvars, /**< number of start time variables (activities) */
9529  SCIP_VAR** vars, /**< array of start time variables */
9530  int* durations, /**< array of durations */
9531  int* demands, /**< array of demands */
9532  int* capacity, /**< pointer to store the changed cumulative capacity */
9533  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9534  int* nchgsides /**< pointer to count number of side changes */
9535  )
9536 { /*lint --e{715}*/
9537  SCIP_Longint gcd;
9538  int mindemand1;
9539  int mindemand2;
9540  int v;
9541 
9542  if( *capacity == 1 || nvars <= 1 )
9543  return SCIP_OKAY;
9544 
9545  assert(demands[nvars-1] <= *capacity);
9546  assert(demands[nvars-2] <= *capacity);
9547 
9548  gcd = (SCIP_Longint)demands[nvars-1];
9549  mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9550  mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9551 
9552  for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9553  {
9554  assert(mindemand1 <= mindemand2);
9555  assert(demands[v] <= *capacity);
9556 
9557  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9558 
9559  if( mindemand1 > demands[v] )
9560  {
9561  mindemand2 = mindemand1;
9562  mindemand1 = demands[v];
9563  }
9564  else if( mindemand2 > demands[v] )
9565  mindemand2 = demands[v];
9566  }
9567 
9568  if( mindemand1 + mindemand2 > *capacity )
9569  {
9570  SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9571 
9572  for( v = 0; v < nvars; ++v )
9573  demands[v] = 1;
9574 
9575  (*capacity) = 1;
9576 
9577  (*nchgcoefs) += nvars;
9578  (*nchgsides)++;
9579  }
9580  else if( gcd >= 2 )
9581  {
9582  SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9583 
9584  for( v = 0; v < nvars; ++v )
9585  demands[v] /= gcd;
9586 
9587  (*capacity) /= gcd;
9588 
9589  (*nchgcoefs) += nvars;
9590  (*nchgsides)++;
9591  }
9592 
9593  return SCIP_OKAY;
9594 }
9595 
9596 /** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9597  * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9598  * capacity since in that case none of the jobs can run in parallel
9599  */
9600 static
9602  SCIP* scip, /**< SCIP data structure */
9603  SCIP_CONS* cons, /**< cumulative constraint */
9604  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9605  int* nchgsides /**< pointer to count number of side changes */
9606  )
9607 {
9608  SCIP_CONSDATA* consdata;
9609  int capacity;
9610 
9611  assert(nchgcoefs != NULL);
9612  assert(nchgsides != NULL);
9613  assert(!SCIPconsIsModifiable(cons));
9614 
9615  consdata = SCIPconsGetData(cons);
9616  assert(consdata != NULL);
9617 
9618  if( consdata->normalized )
9619  return SCIP_OKAY;
9620 
9621  capacity = consdata->capacity;
9622 
9623  /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9624 
9625  SCIP_CALL( normalizeCumulativeCondition(scip, consdata->nvars, consdata->vars, consdata->durations,
9626  consdata->demands, &consdata->capacity, nchgcoefs, nchgsides) );
9627 
9628  consdata->normalized = TRUE;
9629 
9630  if( capacity > consdata->capacity )
9631  consdata->varbounds = FALSE;
9632 
9633  return SCIP_OKAY;
9634 }
9635 
9636 /** computes for the given cumulative condition the effective horizon */
9637 static
9639  SCIP* scip, /**< SCIP data structure */
9640  int nvars, /**< number of variables (jobs) */
9641  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9642  int* durations, /**< array containing corresponding durations */
9643  int* demands, /**< array containing corresponding demands */
9644  int capacity, /**< available cumulative capacity */
9645  int* hmin, /**< pointer to store the left bound of the effective horizon */
9646  int* hmax, /**< pointer to store the right bound of the effective horizon */
9647  int* split /**< point were the cumulative condition can be split */
9648  )
9649 {
9650  SCIP_PROFILE* profile;
9651 
9652  /* create empty resource profile with infinity resource capacity */
9653  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9654 
9655  /* create worst case resource profile */
9656  SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
9657 
9658  /* print resource profile in if SCIP_DEBUG is defined */
9659  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
9660 
9661  /* computes the first time point where the resource capacity can be violated */
9662  (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9663 
9664  /* computes the first time point where the resource capacity is satisfied for sure */
9665  (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9666 
9667  (*split) = (*hmax);
9668 
9669  if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9670  {
9671  int* timepoints;
9672  int* loads;
9673  int ntimepoints;
9674  int t;
9675 
9676  /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9677  * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9678  * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9679  * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9680  * explain the certain "old" bound changes
9681  */
9682 
9683  /* search for time points */
9684  ntimepoints = SCIPprofileGetNTimepoints(profile);
9685  timepoints = SCIPprofileGetTimepoints(profile);
9686  loads = SCIPprofileGetLoads(profile);
9687 
9688  /* 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 */
9689  for( t = 0; t < ntimepoints; ++t )
9690  {
9691  /* ignore all time points before the effective horizon */
9692  if( timepoints[t] <= *hmin )
9693  continue;
9694 
9695  /* ignore all time points after the effective horizon */
9696  if( timepoints[t] >= *hmax )
9697  break;
9698 
9699  /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9700  * can split the cumulative constraint into two cumulative constraints
9701  */
9702  if( loads[t] <= capacity )
9703  {
9704  (*split) = timepoints[t];
9705  break;
9706  }
9707  }
9708  }
9709 
9710  /* free worst case profile */
9711  SCIPprofileFree(&profile);
9712 
9713  return SCIP_OKAY;
9714 }
9715 
9716 /** creates and adds a cumulative constraint */
9717 static
9719  SCIP* scip, /**< SCIP data structure */
9720  const char* name, /**< name of constraint */
9721  int nvars, /**< number of variables (jobs) */
9722  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9723  int* durations, /**< array containing corresponding durations */
9724  int* demands, /**< array containing corresponding demands */
9725  int capacity, /**< available cumulative capacity */
9726  int hmin, /**< left bound of time axis to be considered (including hmin) */
9727  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9728  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9729  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9730  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9731  * Usually set to TRUE. */
9732  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9733  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9734  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9735  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9736  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9737  * Usually set to TRUE. */
9738  SCIP_Bool local, /**< is constraint only valid locally?
9739  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9740  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9741  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9742  * adds coefficients to this constraint. */
9743  SCIP_Bool dynamic, /**< is constraint subject to aging?
9744  * Usually set to FALSE. Set to TRUE for own cuts which
9745  * are seperated as constraints. */
9746  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9747  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9748  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9749  * if it may be moved to a more global node?
9750  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9751  )
9752 {
9753  SCIP_CONS* cons;
9754 
9755  /* creates cumulative constraint and adds it to problem */
9756  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9757  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9758 
9759  /* adjust the effective time horizon of the new constraint */
9760  SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9761  SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9762 
9763  /* add and release new cumulative constraint */
9764  SCIP_CALL( SCIPaddCons(scip, cons) );
9765  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9766 
9767  return SCIP_OKAY;
9768 }
9769 
9770 /** computes the effective horizon and checks if the constraint can be decompsed */
9771 static
9773  SCIP* scip, /**< SCIP data structure */
9774  SCIP_CONS* cons, /**< cumulative constraint */
9775  int* ndelconss, /**< pointer to store the number of deleted constraints */
9776  int* naddconss, /**< pointer to store the number of added constraints */
9777  int* nchgsides /**< pointer to store the number of changed sides */
9778  )
9779 {
9780  SCIP_CONSDATA* consdata;
9781  int hmin;
9782  int hmax;
9783  int split;
9784 
9785  consdata = SCIPconsGetData(cons);
9786  assert(consdata != NULL);
9787 
9788  if( consdata->nvars <= 1 )
9789  return SCIP_OKAY;
9790 
9791  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9792  consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9793 
9794  /* check if this time point improves the effective horizon */
9795  if( consdata->hmin < hmin )
9796  {
9797  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9798 
9799  consdata->hmin = hmin;
9800  (*nchgsides)++;
9801  }
9802 
9803  /* check if this time point improves the effective horizon */
9804  if( consdata->hmax > hmax )
9805  {
9806  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9807  consdata->hmax = hmax;
9808  (*nchgsides)++;
9809  }
9810 
9811  /* check if the constraint is redundant */
9812  if( consdata->hmax <= consdata->hmin )
9813  {
9814  SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9815  SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9816 
9817  SCIP_CALL( SCIPdelCons(scip, cons) );
9818  (*ndelconss)++;
9819  }
9820  else if( consdata->hmin < split && split < consdata->hmax )
9821  {
9822  char name[SCIP_MAXSTRLEN];
9823  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9824 
9825  SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9826  SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9827 
9828  assert(split < consdata->hmax);
9829 
9830  /* creates cumulative constraint and adds it to problem */
9831  SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9832  consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9835 
9836  /* adjust the effective time horizon of the constraint */
9837  consdata->hmax = split;
9838 
9839  assert(consdata->hmin < consdata->hmax);
9840 
9841  /* for the statistic we count the number of time we decompose a cumulative constraint */
9843  (*naddconss)++;
9844  }
9845 
9846  return SCIP_OKAY;
9847 }
9848 
9849 
9850 /** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9851  *
9852  * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9853  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9854  *
9855  * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9856  * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9857  * down-lock of the corresponding start time variable can be removed.
9858  *
9859  * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9860  * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9861  * negative, than the job can be dual fixed to its earlier start time (est).
9862  *
9863  * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9864  * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9865  * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9866  *
9867  * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9868  * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9869  * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9870  * form variable domain is dual feasible.
9871  *
9872  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9873  * the cumulative condition; The deletion has to be done later.
9874  */
9875 static
9877  SCIP* scip, /**< SCIP data structure */
9878  int nvars, /**< number of start time variables (activities) */
9879  SCIP_VAR** vars, /**< array of start time variables */
9880  int* durations, /**< array of durations */
9881  int hmin, /**< left bound of time axis to be considered (including hmin) */
9882  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9883  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9884  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9885  SCIP_CONS* cons, /**< underlying constraint, or NULL */
9886  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9887  int* nfixedvars, /**< pointer to store the number of fixed variables */
9888  int* nchgsides, /**< pointer to store the number of changed sides */
9889  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9890  )
9891 {
9892  SCIP_Real* downimpllbs;
9893  SCIP_Real* downimplubs;
9894  SCIP_Real* downproplbs;
9895  SCIP_Real* downpropubs;
9896  SCIP_Real* upimpllbs;
9897  SCIP_Real* upimplubs;
9898  SCIP_Real* upproplbs;
9899  SCIP_Real* uppropubs;
9900 
9901  int firstminect;
9902  int secondminect;
9903  int v;
9904 
9905  /* get temporary memory for storing probing results needed for step (4) and (5) */
9906  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9907  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9908  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9909  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9910  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9911  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9912  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9913  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9914 
9915  assert(scip != NULL);
9916  assert(nvars > 1);
9917  assert(cons != NULL);
9918 
9919  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9920 
9921  firstminect = INT_MAX;
9922  secondminect = INT_MAX;
9923 
9924  /* compute the two smallest earlier completion times; which are needed for step (5) */
9925  for( v = 0; v < nvars; ++v )
9926  {
9927  int ect;
9928 
9929  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9930 
9931  if( ect < firstminect )
9932  {
9933  secondminect = firstminect;
9934  firstminect = ect;
9935  }
9936  else if( ect < secondminect )
9937  secondminect = ect;
9938  }
9939 
9940  /* loop over all jobs and check if one of the 5 reductions can be applied */
9941  for( v = 0; v < nvars; ++v )
9942  {
9943  SCIP_VAR* var;
9944  int duration;
9945 
9946  int alternativelb;
9947  int minect;
9948  int est;
9949  int ect;
9950  int lst;
9951  int lct;
9952 
9953  var = vars[v];
9954  assert(var != NULL);
9955 
9956  duration = durations[v];
9957  assert(duration > 0);
9958 
9959  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
9960  * time (lct)
9961  */
9962  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9963  ect = est + duration;
9964  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9965  lct = lst + duration;
9966 
9967  /* compute the earliest completion time of all remaining jobs */
9968  if( ect == firstminect )
9969  minect = secondminect;
9970  else
9971  minect = firstminect;
9972 
9973  /* compute potential alternative lower bound (step (4) and (5)) */
9974  alternativelb = MAX(hmin+1, minect);
9975  alternativelb = MIN(alternativelb, hmax);
9976 
9977  if( lct <= hmin )
9978  {
9979  /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
9980  * cumulative condition
9981  */
9982  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
9983  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
9984 
9985  /* mark variable to be irrelevant */
9986  irrelevants[v] = TRUE;
9987 
9988  /* for the statistic we count the number of jobs which are irrelevant */
9989  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9990  }
9991  else if( lst <= hmin && SCIPconsIsChecked(cons) )
9992  {
9993  /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
9994  * so the down lock can be omitted
9995  */
9996 
9997  assert(downlocks != NULL);
9998  assert(uplocks != NULL);
9999 
10000  if( !uplocks[v] )
10001  {
10002  /* the variables has no up lock and we can also remove the down lock;
10003  * => lst <= hmin and ect >= hmax
10004  * => remove job and reduce capacity by the demand of that job
10005  *
10006  * We mark the job to be deletable. The removement together with the capacity reducion is done later
10007  */
10008 
10009  SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
10010  SCIPvarGetName(var), ect - duration, lst, duration);
10011 
10012  /* mark variable to be irrelevant */
10013  irrelevants[v] = TRUE;
10014 
10015  /* for the statistic we count the number of jobs which always run during the effective horizon */
10017  }
10018 
10019  if( downlocks[v] )
10020  {
10021  SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
10022  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10023 
10024  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
10025  downlocks[v] = FALSE;
10026  (*nchgsides)++;
10027 
10028  /* for the statistic we count the number of removed locks */
10030  }
10031  }
10032  else if( ect <= hmin )
10033  {
10034  /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
10035  * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
10036  * removed form the cumulative condition after it was fixed to its earliest start time
10037  */
10038 
10039  /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
10040  * bound;
10041  */
10042  if( downlocks != NULL && SCIPconsIsChecked(cons) )
10043  {
10044  /* fix integer start time variable if possible to it lower bound */
10045  SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
10046  }
10047 
10048  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10049  {
10050  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
10051  SCIPvarGetName(var), ect - duration, lst, duration);
10052 
10053  /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
10054  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
10055 
10056  /* mark variable to be irrelevant */
10057  irrelevants[v] = TRUE;
10058 
10059  /* for the statistic we count the number of jobs which are dual fixed */
10061  }
10062  }
10063  else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10064  {
10065  assert(downlocks != NULL);
10066 
10067  /* check step (4) and (5) */
10068 
10069  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10070  * is in favor of rounding the variable down
10071  */
10072  if( SCIPvarGetNLocksDown(var) == (int)(downlocks[v]) )
10073  {
10074  SCIP_Bool roundable;
10075 
10076  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10077 
10078  if( roundable )
10079  {
10080  if( alternativelb > lst )
10081  {
10082  SCIP_Bool infeasible;
10083  SCIP_Bool fixed;
10084 
10085  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10086  assert(!infeasible);
10087  assert(fixed);
10088 
10089  (*nfixedvars)++;
10090 
10091  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10092  * constraints
10093  */
10095  }
10096  else
10097  {
10098  SCIP_Bool success;
10099 
10100  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10101  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10102  * infeasible we can apply the dual reduction; otherwise we do nothing
10103  */
10104  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10105  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10106  nfixedvars, &success, cutoff) );
10107 
10108  if( success )
10109  {
10111  }
10112  }
10113  }
10114  }
10115  }
10116 
10117  SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10118  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10119  }
10120 
10121  /* free temporary memory */
10122  SCIPfreeBufferArray(scip, &uppropubs);
10123  SCIPfreeBufferArray(scip, &upproplbs);
10124  SCIPfreeBufferArray(scip, &upimplubs);
10125  SCIPfreeBufferArray(scip, &upimpllbs);
10126  SCIPfreeBufferArray(scip, &downpropubs);
10127  SCIPfreeBufferArray(scip, &downproplbs);
10128  SCIPfreeBufferArray(scip, &downimplubs);
10129  SCIPfreeBufferArray(scip, &downimpllbs);
10130 
10131  return SCIP_OKAY;
10132 }
10133 
10134 /** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10135  *
10136  * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10137  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10138  *
10139  * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10140  * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10141  * up-lock of the corresponding start time variable can be removed.
10142  *
10143  * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10144  * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10145  * positive, than the job can be dual fixed to its latest start time (lst).
10146  *
10147  * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10148  * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10149  * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10150  * of the corresponding job).
10151 
10152  * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10153  * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10154  * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10155  * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10156  *
10157  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10158  * the cumulative condition; The deletion has to be done later.
10159  */
10160 static
10162  SCIP* scip, /**< SCIP data structure */
10163  int nvars, /**< number of start time variables (activities) */
10164  SCIP_VAR** vars, /**< array of start time variables */
10165  int* durations, /**< array of durations */
10166  int hmin, /**< left bound of time axis to be considered (including hmin) */
10167  int hmax, /**< right bound of time axis to be considered (not including hmax) */
10168  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10169  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10170  SCIP_CONS* cons, /**< underlying constraint, or NULL */
10171  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10172  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10173  int* nchgsides, /**< pointer to store the number of changed sides */
10174  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10175  )
10176 {
10177  SCIP_Real* downimpllbs;
10178  SCIP_Real* downimplubs;
10179  SCIP_Real* downproplbs;
10180  SCIP_Real* downpropubs;
10181  SCIP_Real* upimpllbs;
10182  SCIP_Real* upimplubs;
10183  SCIP_Real* upproplbs;
10184  SCIP_Real* uppropubs;
10185 
10186  int firstmaxlst;
10187  int secondmaxlst;
10188  int v;
10189 
10190  /* get temporary memory for storing probing results needed for step (4) and (5) */
10191  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10192  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10193  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10194  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10195  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10196  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10197  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10198  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10199 
10200  assert(scip != NULL);
10201  assert(nvars > 1);
10202  assert(cons != NULL);
10203 
10204  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10205 
10206  firstmaxlst = INT_MIN;
10207  secondmaxlst = INT_MIN;
10208 
10209  /* compute the two largest latest start times; which are needed for step (5) */
10210  for( v = 0; v < nvars; ++v )
10211  {
10212  int lst;
10213 
10214  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(vars[v]));
10215 
10216  if( lst > firstmaxlst )
10217  {
10218  secondmaxlst = firstmaxlst;
10219  firstmaxlst = lst;
10220  }
10221  else if( lst > secondmaxlst )
10222  secondmaxlst = lst;
10223  }
10224 
10225  /* loop over all jobs and check if one of the 5 reductions can be applied */
10226  for( v = 0; v < nvars; ++v )
10227  {
10228  SCIP_VAR* var;
10229  int duration;
10230 
10231  int alternativeub;
10232  int maxlst;
10233  int est;
10234  int ect;
10235  int lst;
10236 
10237  var = vars[v];
10238  assert(var != NULL);
10239 
10240  duration = durations[v];
10241  assert(duration > 0);
10242 
10243  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10244  * time (lct)
10245  */
10246  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10247  ect = est + duration;
10248  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10249 
10250  /* compute the latest start time of all remaining jobs */
10251  if( lst == firstmaxlst )
10252  maxlst = secondmaxlst;
10253  else
10254  maxlst = firstmaxlst;
10255 
10256  /* compute potential alternative upper bound (step (4) and (5)) */
10257  alternativeub = MIN(hmax - 1, maxlst) - duration;
10258  alternativeub = MAX(alternativeub, hmin);
10259 
10260  if( est >= hmax )
10261  {
10262  /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10263  * cumulative condition
10264  */
10265  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10266  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10267 
10268  /* mark variable to be irrelevant */
10269  irrelevants[v] = TRUE;
10270 
10271  /* for the statistic we count the number of jobs which are irrelevant */
10272  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10273  }
10274  else if( ect >= hmax && SCIPconsIsChecked(cons) )
10275  {
10276  assert(downlocks != NULL);
10277  assert(uplocks != NULL);
10278 
10279  /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10280  * so the up lock can be omitted
10281  */
10282 
10283  if( !downlocks[v] )
10284  {
10285  /* the variables has no down lock and we can also remove the up lock;
10286  * => lst <= hmin and ect >= hmax
10287  * => remove job and reduce capacity by the demand of that job
10288  */
10289  SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10290  SCIPvarGetName(var), est, lst, duration);
10291 
10292  /* mark variable to be irrelevant */
10293  irrelevants[v] = TRUE;
10294 
10295  /* for the statistic we count the number of jobs which always run during the effective horizon */
10297  }
10298 
10299  if( uplocks[v] )
10300  {
10301  SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10302  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10303 
10304  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10305  uplocks[v] = FALSE;
10306  (*nchgsides)++;
10307 
10308  /* for the statistic we count the number of removed locks */
10310  }
10311  }
10312  else if( lst >= hmax )
10313  {
10314  /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10315  * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10316  * removed form the cumulative condition after it was fixed to its latest start time
10317  */
10318 
10319  /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10320  * bound
10321  */
10322  if( uplocks != NULL && SCIPconsIsChecked(cons) )
10323  {
10324  /* fix integer start time variable if possible to its upper bound */
10325  SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10326  }
10327 
10328  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10329  {
10330  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10331  SCIPvarGetName(var), est, lst, duration);
10332 
10333  /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10334  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10335 
10336  /* mark variable to be irrelevant */
10337  irrelevants[v] = TRUE;
10338 
10339  /* for the statistic we count the number of jobs which are dual fixed */
10341  }
10342  }
10343  else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10344  {
10345  assert(uplocks != NULL);
10346 
10347  /* check step (4) and (5) */
10348 
10349  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10350  * is in favor of rounding the variable down
10351  */
10352  if( SCIPvarGetNLocksUp(var) == (int)(uplocks[v]) )
10353  {
10354  SCIP_Bool roundable;
10355 
10356  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10357 
10358  if( roundable )
10359  {
10360  if( alternativeub < est )
10361  {
10362  SCIP_Bool infeasible;
10363  SCIP_Bool fixed;
10364 
10365  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10366  assert(!infeasible);
10367  assert(fixed);
10368 
10369  (*nfixedvars)++;
10370 
10371  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10372  * constraints
10373  */
10375  }
10376  else
10377  {
10378  SCIP_Bool success;
10379 
10380  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10381  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10382  * in infeasible we can apply the dual reduction; otherwise we do nothing
10383  */
10384  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10385  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10386  nfixedvars, &success, cutoff) );
10387 
10388  if( success )
10389  {
10391  }
10392  }
10393  }
10394  }
10395  }
10396  }
10397 
10398  /* free temporary memory */
10399  SCIPfreeBufferArray(scip, &uppropubs);
10400  SCIPfreeBufferArray(scip, &upproplbs);
10401  SCIPfreeBufferArray(scip, &upimplubs);
10402  SCIPfreeBufferArray(scip, &upimpllbs);
10403  SCIPfreeBufferArray(scip, &downpropubs);
10404  SCIPfreeBufferArray(scip, &downproplbs);
10405  SCIPfreeBufferArray(scip, &downimplubs);
10406  SCIPfreeBufferArray(scip, &downimpllbs);
10407 
10408  return SCIP_OKAY;
10409 }
10410 
10411 /** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10412 static
10414  SCIP* scip, /**< SCIP data structure */
10415  SCIP_CONS* cons, /**< cumulative constraint */
10416  int* nfixedvars, /**< pointer to store the number of fixed variables */
10417  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10418  int* nchgsides, /**< pointer to store the number of changed sides */
10419  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10420  )
10421 {
10422  SCIP_CONSDATA* consdata;
10423  SCIP_Bool* irrelevants;
10424  int nvars;
10425  int v;
10426 
10427  assert(scip != NULL);
10428  assert(cons != NULL);
10429  assert(!(*cutoff));
10430 
10431  consdata = SCIPconsGetData(cons);
10432  assert(consdata != NULL);
10433 
10434  nvars = consdata->nvars;
10435 
10436  if( nvars <= 1 )
10437  return SCIP_OKAY;
10438 
10439  SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10440  BMSclearMemoryArray(irrelevants, nvars);
10441 
10442  /* presolve constraint form the earlier start time point of view */
10443  SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10444  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10445  irrelevants, nfixedvars, nchgsides, cutoff) );
10446 
10447  /* presolve constraint form the latest completion time point of view */
10448  SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10449  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10450  irrelevants, nfixedvars, nchgsides, cutoff) );
10451 
10452  /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10453  * order to ensure a correct behaviour
10454  */
10455  for( v = nvars-1; v >= 0; --v )
10456  {
10457  if( irrelevants[v] )
10458  {
10459  SCIP_VAR* var;
10460  int ect;
10461  int lst;
10462 
10463  var = consdata->vars[v];
10464  assert(var != NULL);
10465 
10466  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10467  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10468 
10469  /* check if the jobs runs completely during the effective horizon */
10470  if( lst <= consdata->hmin && ect >= consdata->hmax )
10471  {
10472  if( consdata->capacity < consdata->demands[v] )
10473  {
10474  *cutoff = TRUE;
10475  break;
10476  }
10477 
10478  consdata->capacity -= consdata->demands[v];
10479  consdata->varbounds = FALSE;
10480  }
10481 
10482  SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10483  (*nchgcoefs)++;
10484  }
10485  }
10486 
10487  SCIPfreeBufferArray(scip, &irrelevants);
10488 
10489  return SCIP_OKAY;
10490 }
10491 
10492 /** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10493 static
10495  SCIP* scip, /**< SCIP data structure */
10496  SCIP_CONSDATA* consdata, /**< constraint data */
10497  int* startindices, /**< permutation with rspect to the start times */
10498  int curtime, /**< current point in time */
10499  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10500  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10501  SCIP_Longint** demands, /**< pointer to array storing the demands */
10502  int* ndemands /**< pointer to store the number of different demands */
10503  )
10504 {
10505  int startindex;
10506  int ncountedvars;
10507 
10508  assert(demands != NULL);
10509  assert(ndemands != NULL);
10510 
10511  ncountedvars = 0;
10512  startindex = nstarted - 1;
10513 
10514  *ndemands = 0;
10515 
10516  /* search for the (nstarted - nfinished) jobs which are active at curtime */
10517  while( nstarted - nfinished > ncountedvars )
10518  {
10519  SCIP_VAR* var;
10520  int endtime;
10521  int varidx;
10522 
10523  /* collect job information */
10524  varidx = startindices[startindex];
10525  assert(varidx >= 0 && varidx < consdata->nvars);
10526 
10527  var = consdata->vars[varidx];
10528  assert(var != NULL);
10529 
10530  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10531 
10532  /* check the end time of this job is larger than the curtime; in this case the job is still running */
10533  if( endtime > curtime )
10534  {
10535  if( consdata->demands[varidx] < consdata->capacity )
10536  {
10537  (*demands)[*ndemands] = consdata->demands[varidx];
10538  (*ndemands)++;
10539  }
10540  ncountedvars++;
10541  }
10542 
10543  startindex--;
10544  }
10545 
10546  return SCIP_OKAY;
10547 }
10548 
10549 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10550  * constraint
10551  */
10552 static
10554  SCIP* scip, /**< SCIP data structure */
10555  SCIP_CONS* cons, /**< constraint to be checked */
10556  int* startindices, /**< permutation with rspect to the start times */
10557  int curtime, /**< current point in time */
10558  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10559  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10560  int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10561  )
10562 {
10563  SCIP_CONSDATA* consdata;
10564  SCIP_Longint* demands;
10565  SCIP_Real* profits;
10566  int* items;
10567  int ndemands;
10568  SCIP_Bool success;
10569  SCIP_Real solval;
10570  int j;
10571  assert(nstarted > nfinished);
10572 
10573  consdata = SCIPconsGetData(cons);
10574  assert(consdata != NULL);
10575  assert(consdata->nvars > 0);
10576  assert(consdata->capacity > 0);
10577 
10578  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10579  ndemands = 0;
10580 
10581  /* get demand array to initialize knapsack problem */
10582  SCIP_CALL( collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands) );
10583 
10584  /* create array for profits */
10585  SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10586  SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10587  for( j = 0; j < ndemands; ++j )
10588  {
10589  profits[j] = (SCIP_Real) demands[j];
10590  items[j] = j;/* this is only a dummy value*/
10591  }
10592 
10593  /* solve knapsack problem and get maximum capacity usage <= capacity */
10594  SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10595  items, NULL, NULL, NULL, NULL, &solval, &success) );
10596 
10597  assert(SCIPisFeasIntegral(scip, solval));
10598 
10599  /* store result */
10600  *bestcapacity = SCIPconvertRealToInt(scip, solval);
10601 
10602  SCIPfreeBufferArray(scip, &items);
10603  SCIPfreeBufferArray(scip, &profits);
10604  SCIPfreeBufferArray(scip, &demands);
10605 
10606  return SCIP_OKAY;
10607 }
10608 
10609 /** try to tighten the capacity
10610  * -- using DP for knapsack, we find the maximum possible capacity usage
10611  * -- neglects hmin and hmax, such that it is also able to check solutions globally
10612  */
10613 static
10615  SCIP* scip, /**< SCIP data structure */
10616  SCIP_CONS* cons, /**< cumulative constraint */
10617  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10618  int* nchgsides /**< pointer to store the number of changed sides */
10619  )
10620 {
10621  SCIP_CONSDATA* consdata;
10622  int* starttimes; /* stores when each job is starting */
10623  int* endtimes; /* stores when each job ends */
10624  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10625  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10626 
10627  int nvars; /* number of activities for this constraint */
10628  int freecapacity; /* remaining capacity */
10629  int curtime; /* point in time which we are just checking */
10630  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10631 
10632  int bestcapacity;
10633 
10634  int j;
10635 
10636  assert(scip != NULL);
10637  assert(cons != NULL);
10638  assert(nchgsides != NULL);
10639 
10640  consdata = SCIPconsGetData(cons);
10641  assert(consdata != NULL);
10642 
10643  nvars = consdata->nvars;
10644 
10645  /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10646  if( nvars <= 1 || consdata->capacity <= 1 )
10647  return SCIP_OKAY;
10648 
10649  assert(consdata->vars != NULL);
10650 
10651  SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10652  SCIPconsGetName(cons), consdata->capacity);
10653 
10654  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10655  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10656  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10657  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10658 
10659  /* create event point arrays */
10660  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10661  starttimes, endtimes, startindices, endindices, FALSE);
10662 
10663  bestcapacity = 1;
10664  endindex = 0;
10665  freecapacity = consdata->capacity;
10666 
10667  /* check each startpoint of a job whether the capacity is kept or not */
10668  for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10669  {
10670  curtime = starttimes[j];
10671  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10672 
10673  /* remove the capacity requirments for all job which start at the curtime */
10674  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10675 
10676  /* add the capacity requirments for all job which end at the curtime */
10677  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10678 
10679  assert(freecapacity <= consdata->capacity);
10680  assert(endindex <= nvars);
10681 
10682  /* endindex - points to the next job which will finish */
10683  /* j - points to the last job that has been released */
10684 
10685  /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10686  if( freecapacity < 0 )
10687  {
10688  int newcapacity;
10689 
10690  newcapacity = 1;
10691 
10692  /* get best possible upper bound on capacity usage */
10693  SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10694 
10695  /* update bestcapacity */
10696  bestcapacity = MAX(bestcapacity, newcapacity);
10697  SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10698  }
10699 
10700  /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10701  if( freecapacity > 0 && freecapacity != consdata->capacity )
10702  {
10703  bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10704  SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10705  }
10706 
10707  /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10708  if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10709  {
10710  /* if demands[startindices[j]] == cap then exactly that job is running */
10711  SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10712  bestcapacity = consdata->capacity;
10713  break;
10714  }
10715  } /*lint --e{850}*/
10716 
10717  /* free all buffer arrays */
10718  SCIPfreeBufferArray(scip, &endindices);
10719  SCIPfreeBufferArray(scip, &startindices);
10720  SCIPfreeBufferArray(scip, &endtimes);
10721  SCIPfreeBufferArray(scip, &starttimes);
10722 
10723  /* check whether capacity can be tightened and whether demands need to be adjusted */
10724  if( bestcapacity < consdata->capacity )
10725  {
10726  /* cppcheck-suppress unassignedVariable */
10727  int oldnchgcoefs;
10728 
10729  SCIPdebug(oldnchgcoefs = *nchgcoefs; )
10730 
10731  SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10732  SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10733 
10734  for( j = 0; j < nvars; ++j )
10735  {
10736  if( consdata->demands[j] == consdata->capacity )
10737  {
10738  consdata->demands[j] = bestcapacity;
10739  (*nchgcoefs)++;
10740  }
10741  }
10742 
10743  consdata->capacity = bestcapacity;
10744  (*nchgsides)++;
10745 
10746  SCIPdebugMsgPrint(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs);
10747 
10748  consdata->varbounds = FALSE;
10749  }
10750 
10751  return SCIP_OKAY;
10752 }
10753 
10754 /** tries to change coefficients:
10755  * demand_j < cap && all other parallel jobs in conflict
10756  * ==> set demand_j := cap
10757  */
10758 static
10760  SCIP* scip, /**< SCIP data structure */
10761  SCIP_CONS* cons, /**< cumulative constraint */
10762  int* nchgcoefs /**< pointer to count total number of changed coefficients */
10763  )
10764 {
10765  SCIP_CONSDATA* consdata;
10766  int nvars;
10767  int j;
10768  int oldnchgcoefs;
10769  int mindemand;
10770 
10771  assert(scip != NULL);
10772  assert(cons != NULL);
10773  assert(nchgcoefs != NULL);
10774 
10775  /* get constraint data for some parameter testings only! */
10776  consdata = SCIPconsGetData(cons);
10777  assert(consdata != NULL);
10778 
10779  nvars = consdata->nvars;
10780  oldnchgcoefs = *nchgcoefs;
10781 
10782  if( nvars <= 0 )
10783  return SCIP_OKAY;
10784 
10785  /* PRE1:
10786  * check all jobs j whether: r_j + r_min > capacity holds
10787  * if so: adjust r_j to capacity
10788  */
10789  mindemand = consdata->demands[0];
10790  for( j = 0; j < nvars; ++j )
10791  {
10792  mindemand = MIN(mindemand, consdata->demands[j]);
10793  }
10794 
10795  /*check each job */
10796  for( j = 0; j < nvars; ++j )
10797  {
10798  if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10799  {
10800  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10801  consdata->demands[j], consdata->capacity);
10802  consdata->demands[j] = consdata->capacity;
10803  (*nchgcoefs)++;
10804  }
10805  }
10806 
10807  /* PRE2:
10808  * check for each job (with d_j < cap)
10809  * whether it is disjunctive to all others over the time horizon
10810  */
10811  for( j = 0; j < nvars; ++j )
10812  {
10813  SCIP_Bool chgcoef;
10814  int est_j;
10815  int lct_j;
10816  int i;
10817 
10818  assert(consdata->demands[j] <= consdata->capacity);
10819 
10820  if( consdata->demands[j] == consdata->capacity )
10821  continue;
10822 
10823  chgcoef = TRUE;
10824 
10825  est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10826  lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10827 
10828  for( i = 0; i < nvars; ++i )
10829  {
10830  int est_i;
10831  int lct_i;
10832 
10833  if( i == j )
10834  continue;
10835 
10836  est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10837  lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10838 
10839  if( est_i >= lct_j || est_j >= lct_i )
10840  continue;
10841 
10842  if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10843  {
10844  chgcoef = FALSE;
10845  break;
10846  }
10847  }
10848 
10849  if( chgcoef )
10850  {
10851  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10852  consdata->demands[j], consdata->capacity);
10853  consdata->demands[j] = consdata->capacity;
10854  (*nchgcoefs)++;
10855  }
10856 
10857  }
10858 
10859  if( (*nchgcoefs) > oldnchgcoefs )
10860  {
10861  SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10862  (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10863  }
10864 
10865  return SCIP_OKAY;
10866 }
10867 
10868 #if 0
10869 /** try to reformulate constraint by replacing certain jobs */
10870 static
10871 SCIP_RETCODE reformulateCons(
10872  SCIP* scip, /**< SCIP data structure */
10873  SCIP_CONS* cons, /**< cumulative constraint */
10874  int* naggrvars /**< pointer to store the number of aggregated variables */
10875  )
10876 {
10877  SCIP_CONSDATA* consdata;
10878  int hmin;
10879  int hmax;
10880  int nvars;
10881  int v;
10882 
10883  consdata = SCIPconsGetData(cons);
10884  assert(cons != NULL);
10885 
10886  nvars = consdata->nvars;
10887  assert(nvars > 1);
10888 
10889  hmin = consdata->hmin;
10890  hmax = consdata->hmax;
10891  assert(hmin < hmax);
10892 
10893  for( v = 0; v < nvars; ++v )
10894  {
10895  SCIP_VAR* var;
10896  int duration;
10897  int est;
10898  int ect;
10899  int lst;
10900  int lct;
10901 
10902  var = consdata->vars[v];
10903  assert(var != NULL);
10904 
10905  duration = consdata->durations[v];
10906 
10907  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10908  ect = est + duration;
10909  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10910  lct = lst + duration;
10911 
10912  /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10913  assert(lst > hmin || ect < hmax);
10914 
10915  if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10916  {
10917  SCIP_VAR* aggrvar;
10918  char name[SCIP_MAXSTRLEN];
10919  SCIP_Bool infeasible;
10920  SCIP_Bool redundant;
10921  SCIP_Bool aggregated;
10922  int shift;
10923 
10924  shift = est - (hmin - lct + MIN(hmin, ect));
10925  assert(shift > 0);
10926  lst = hmin;
10927  duration = hmin - lct;
10928 
10929  SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10930  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10931 
10932  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10933  SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10934  SCIPvarIsInitial(var), SCIPvarIsRemovable(var), NULL, NULL, NULL, NULL, NULL) );
10935  SCIP_CALL( SCIPaddVar(scip, var) );
10936  SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10937 
10938  assert(!infeasible);
10939  assert(!redundant);
10940  assert(aggregated);
10941 
10942  /* replace variable */
10943  consdata->durations[v] = duration;
10944  consdata->vars[v] = aggrvar;
10945 
10946  /* remove and add locks */
10947  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10948  SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10949 
10950  SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10951 
10952  (*naggrvars)++;
10953  }
10954  }
10955 
10956  return SCIP_OKAY;
10957 }
10958 #endif
10959 
10960 /** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10961 static
10963  SCIP* scip, /**< SCIP data structure */
10964  SCIP_CONS* cons, /**< cumulative constraint */
10965  int* naddconss /**< pointer to store the number of added constraints */
10966  )
10967 {
10968  SCIP_CONSDATA* consdata;
10969  SCIP_VAR** vars;
10970  int* durations;
10971  int* demands;
10972  int capacity;
10973  int halfcapacity;
10974  int mindemand;
10975  int nvars;
10976  int v;
10977 
10978  consdata = SCIPconsGetData(cons);
10979  assert(consdata != NULL);
10980 
10981  capacity = consdata->capacity;
10982 
10983  if( capacity == 1 )
10984  return SCIP_OKAY;
10985 
10986  SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
10987  SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
10988  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10989 
10990  halfcapacity = capacity / 2;
10991  mindemand = consdata->capacity;
10992  nvars = 0;
10993 
10994  /* collect all jobs with demand larger than half of the capacity */
10995  for( v = 0; v < consdata->nvars; ++v )
10996  {
10997  if( consdata->demands[v] > halfcapacity )
10998  {
10999  vars[nvars] = consdata->vars[v];
11000  demands[nvars] = 1;
11001  durations[nvars] = consdata->durations[v];
11002  nvars++;
11003 
11004  mindemand = MIN(mindemand, consdata->demands[v]);
11005  }
11006  }
11007 
11008  if( nvars > 0 )
11009  {
11010  /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
11011  * job is still to large to be scheduled in parallel
11012  */
11013  for( v = 0; v < consdata->nvars; ++v )
11014  {
11015  if( consdata->demands[v] > halfcapacity )
11016  continue;
11017 
11018  if( mindemand + consdata->demands[v] > capacity )
11019  {
11020  demands[nvars] = 1;
11021  durations[nvars] = consdata->durations[v];
11022  vars[nvars] = consdata->vars[v];
11023  nvars++;
11024 
11025  /* @todo create one cumulative constraint and look for another small demand */
11026  break;
11027  }
11028  }
11029 
11030  /* creates cumulative constraint and adds it to problem */
11031  SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
11033  (*naddconss)++;
11034  }
11035 
11036  SCIPfreeBufferArray(scip, &demands);
11037  SCIPfreeBufferArray(scip, &durations);
11038  SCIPfreeBufferArray(scip, &vars);
11039 
11040  return SCIP_OKAY;
11041 }
11042 
11043 /** presolve given constraint */
11044 static
11046  SCIP* scip, /**< SCIP data structure */
11047  SCIP_CONS* cons, /**< cumulative constraint */
11048  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
11049  SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
11050  int* nfixedvars, /**< pointer to store the number of fixed variables */
11051 #if 0
11052  int* naggrvars, /**< pointer to counter which is increased by the number of deduced variable aggregations */
11053 #endif
11054  int* nchgbds, /**< pointer to store the number of changed bounds */
11055  int* ndelconss, /**< pointer to store the number of deleted constraints */
11056  int* naddconss, /**< pointer to store the number of added constraints */
11057  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
11058  int* nchgsides, /**< pointer to store the number of changed sides */
11059  SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
11060  SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
11061  )
11062 {
11063  assert(!SCIPconsIsDeleted(cons));
11064 
11065  /* only perform dual reductions on model constraints */
11066  if( conshdlrdata->dualpresolve && SCIPallowDualReds(scip) )
11067  {
11068  /* computes the effective horizon and checks if the constraint can be decomposed */
11069  SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11070 
11071  if( SCIPconsIsDeleted(cons) )
11072  return SCIP_OKAY;
11073 
11074  /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11075  * fixings (dual reductions)
11076  */
11077  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11078  {
11079  SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11080 
11081  if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11082  return SCIP_OKAY;
11083  }
11084 
11085  SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11086 
11087  if( *cutoff || SCIPconsIsDeleted(cons) )
11088  return SCIP_OKAY;
11089  }
11090 
11091  /* remove jobs which have a demand larger than the capacity */
11092  SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11093  assert((*cutoff) || checkDemands(scip, cons));
11094 
11095  if( *cutoff )
11096  return SCIP_OKAY;
11097 
11098  if( conshdlrdata->normalize )
11099  {
11100  /* divide demands by their greatest common divisor */
11101  SCIP_CALL( normalizeDemands(scip, cons, nchgcoefs, nchgsides) );
11102  }
11103 
11104  /* delete constraint with one job */
11105  SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11106 
11107  if( *cutoff || SCIPconsIsDeleted(cons) )
11108  return SCIP_OKAY;
11109 
11110  if( conshdlrdata->coeftightening )
11111  {
11112  /* try to tighten the capacity */
11113  SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11114 
11115  /* try to tighten the coefficients */
11116  SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11117  }
11118 
11119  assert(checkDemands(scip, cons) || *cutoff);
11120 
11121 #if 0
11122  SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11123 #endif
11124 
11125  return SCIP_OKAY;
11126 }
11127 
11128 /**@name TClique Graph callbacks
11129  *
11130  * @{
11131  */
11132 
11133 /** tclique graph data */
11134 struct TCLIQUE_Graph
11135 {
11136  SCIP_VAR** vars; /**< start time variables each of them is a node */
11137  SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11138  SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11139  SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11140  TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11141  int* ninarcs; /**< number if in arcs for the precedence graph */
11142  int* noutarcs; /**< number if out arcs for the precedence graph */
11143  int* durations; /**< for each node the duration of the corresponding job */
11144  int nnodes; /**< number of nodes */
11145  int size; /**< size of the array */
11146 };
11147 
11148 /** gets number of nodes in the graph */
11149 static
11150 TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11152  assert(tcliquegraph != NULL);
11153 
11154  return tcliquegraph->nnodes;
11155 }
11156 
11157 /** gets weight of nodes in the graph */
11158 static
11159 TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11161  assert(tcliquegraph != NULL);
11162 
11163  return tcliquegraph->weights;
11164 }
11165 
11166 /** returns, whether the edge (node1, node2) is in the graph */
11167 static
11168 TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11170  assert(tcliquegraph != NULL);
11171  assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11172  assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11173 
11174  /* check if an arc exits in the precedence graph */
11175  if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11176  return TRUE;
11177 
11178  /* check if an edge exits in the non-overlapping graph */
11179  if( tcliquegraph->demandmatrix[node1][node2] )
11180  return TRUE;
11181 
11182  return FALSE;
11183 }
11184 
11185 /** selects all nodes from a given set of nodes which are adjacent to a given node
11186  * and returns the number of selected nodes
11187  */
11188 static
11189 TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11191  int nadjnodes;
11192  int i;
11193 
11194  assert(tcliquegraph != NULL);
11195  assert(0 <= node && node < tcliquegraph->nnodes);
11196  assert(nnodes == 0 || nodes != NULL);
11197  assert(adjnodes != NULL);
11198 
11199  nadjnodes = 0;
11200 
11201  for( i = 0; i < nnodes; i++ )
11202  {
11203  /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11204  assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11205  assert(i == 0 || nodes[i-1] < nodes[i]);
11206 
11207  /* check if an edge exists */
11208  if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11209  {
11210  /* current node is adjacent to given node */
11211  adjnodes[nadjnodes] = nodes[i];
11212  nadjnodes++;
11213  }
11214  }
11215 
11216  return nadjnodes;
11217 }
11218 
11219 /** generates cuts using a clique found by algorithm for maximum weight clique
11220  * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11221  */
11222 static
11223 TCLIQUE_NEWSOL(tcliqueNewsolClique)
11224 { /*lint --e{715}*/
11225  SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11226 }
11227 
11228 /** print the tclique graph */
11229 #if 0
11230 static
11231 void tcliquePrint(
11232  SCIP* scip, /**< SCIP data structure */
11233  TCLIQUE_GRAPH* tcliquegraph /**< tclique graph */
11234  )
11235 {
11236  int nnodes;
11237  int i;
11238  int j;
11239 
11240  nnodes = tcliquegraph->nnodes;
11241 
11242  for( i = 0; i < nnodes; ++i )
11243  {
11244  for( j = 0; j < nnodes; ++j )
11245  {
11246  SCIPinfoMessage(scip, NULL, "(%d/%d) ", tcliquegraph->precedencematrix[i][j], tcliquegraph->demandmatrix[i][j]);
11247  }
11248  SCIPinfoMessage(scip, NULL, "\n");
11249  }
11250 }
11251 #endif
11252 
11253 /** @} */
11254 
11255 /** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11256  * job corresponding to variable bound variable (vlbvar)
11257  *
11258  * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11259  */
11260 static
11262  SCIP* scip, /**< SCIP data structure */
11263  SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11264  SCIP_Real vlbcoef, /**< variable bound coefficient */
11265  SCIP_Real vlbconst, /**< variable bound constant */
11266  int duration /**< duration of the variable bound variable */
11267  )
11268 {
11269  if( SCIPisEQ(scip, vlbcoef, 1.0) )
11270  {
11271  if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11272  {
11273  /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11274  return TRUE;
11275  }
11276  }
11277  else
11278  {
11279  SCIP_Real bound;
11280 
11281  bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11282 
11283  if( SCIPisLT(scip, vlbcoef, 1.0) )
11284  {
11285  SCIP_Real ub;
11286 
11287  ub = SCIPvarGetUbLocal(vlbvar);
11288 
11289  /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11290  if( SCIPisLE(scip, ub, bound) )
11291  return TRUE;
11292  }
11293  else
11294  {
11295  SCIP_Real lb;
11296 
11297  assert(SCIPisGT(scip, vlbcoef, 1.0));
11298 
11299  lb = SCIPvarGetLbLocal(vlbvar);
11300 
11301  /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11302  if( SCIPisGE(scip, lb, bound) )
11303  return TRUE;
11304  }
11305  }
11306 
11307  return FALSE;
11308 }
11309 
11310 /** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11311  * job corresponding to variable which is bounded (var)
11312  *
11313  * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11314  */
11315 static
11317  SCIP* scip, /**< SCIP data structure */
11318  SCIP_VAR* var, /**< variable which is bound from above */
11319  SCIP_Real vubcoef, /**< variable bound coefficient */
11320  SCIP_Real vubconst, /**< variable bound constant */
11321  int duration /**< duration of the variable which is bounded from above */
11322  )
11323 {
11324  SCIP_Real vlbcoef;
11325  SCIP_Real vlbconst;
11326 
11327  /* convert the variable upper bound into an variable lower bound */
11328  vlbcoef = 1.0 / vubcoef;
11329  vlbconst = -vubconst / vubcoef;
11330 
11331  return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11332 }
11333 
11334 /** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11335  * others an index larger than the number if active variables
11336  */
11337 static
11339  SCIP* scip, /**< SCIP data structure */
11340  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11341  SCIP_VAR* var, /**< variable for which we want the index */
11342  int* idx /**< pointer to store the index */
11343  )
11344 {
11345  (*idx) = SCIPvarGetProbindex(var);
11346 
11347  if( (*idx) == -1 )
11348  {
11349  if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11350  {
11351  (*idx) = (int)(size_t) SCIPhashmapGetImage(tcliquegraph->varmap, (void*)var);
11352  }
11353  else
11354  {
11355  int pos;
11356  int v;
11357 
11358  /**@todo we might want to add the aggregation path to graph */
11359 
11360  /* check if we have to realloc memory */
11361  if( tcliquegraph->size == tcliquegraph->nnodes )
11362  {
11363  int size;
11364 
11365  size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11366  tcliquegraph->size = size;
11367 
11368  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11369  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11370  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11371  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11372  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11373 
11374  for( v = 0; v < tcliquegraph->nnodes; ++v )
11375  {
11376  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11377  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11378  }
11379  }
11380  assert(tcliquegraph->nnodes < tcliquegraph->size);
11381 
11382  pos = tcliquegraph->nnodes;
11383  assert(pos >= 0);
11384 
11385  tcliquegraph->durations[pos] = 0;
11386  tcliquegraph->weights[pos] = 0;
11387  tcliquegraph->vars[pos] = var;
11388 
11389  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11390  BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11391 
11392  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11393  BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11394 
11395  SCIP_CALL( SCIPhashmapInsert(tcliquegraph->varmap, (void*)var, (void*)(size_t)(pos)) );
11396 
11397  tcliquegraph->nnodes++;
11398 
11399  for( v = 0; v < tcliquegraph->nnodes; ++v )
11400  {
11401  tcliquegraph->precedencematrix[v][pos] = 0;
11402  tcliquegraph->demandmatrix[v][pos] = 0;
11403  }
11404 
11405  (*idx) = tcliquegraph->nnodes;
11406  }
11407  }
11408  else
11409  {
11410  assert(*idx == (int)(size_t)SCIPhashmapGetImage(tcliquegraph->varmap, (void*)var));
11411  }
11412 
11413  assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11414 
11415  return SCIP_OKAY;
11416 }
11417 
11418 /** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11419  *
11420  * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11421  * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11422  *
11423  * (i) b = 1 and c >= d
11424  * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11425  * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11426  *
11427  */
11428 static
11430  SCIP* scip, /**< SCIP data structure */
11431  TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11432  )
11433 {
11434  SCIP_VAR** vars;
11435  int nvars;
11436  int v;
11437 
11438  vars = SCIPgetVars(scip);
11439  nvars = SCIPgetNVars(scip);
11440 
11441  /* try to project each arc of the variable bound graph to precedence condition */
11442  for( v = 0; v < nvars; ++v )
11443  {
11444  SCIP_VAR** vbdvars;
11445  SCIP_VAR* var;
11446  SCIP_Real* vbdcoefs;
11447  SCIP_Real* vbdconsts;
11448  int nvbdvars;
11449  int idx1;
11450  int b;
11451 
11452  var = vars[v];
11453  assert(var != NULL);
11454 
11455  SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11456  assert(idx1 >= 0);
11457 
11458  if( tcliquegraph->durations[idx1] == 0 )
11459  continue;
11460 
11461  vbdvars = SCIPvarGetVlbVars(var);
11462  vbdcoefs = SCIPvarGetVlbCoefs(var);
11463  vbdconsts = SCIPvarGetVlbConstants(var);
11464  nvbdvars = SCIPvarGetNVlbs(var);
11465 
11466  for( b = 0; b < nvbdvars; ++b )
11467  {
11468  int idx2;
11469 
11470  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11471  assert(idx2 >= 0);
11472 
11473  if( tcliquegraph->durations[idx2] == 0 )
11474  continue;
11475 
11476  if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11477  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11478  }
11479 
11480  vbdvars = SCIPvarGetVubVars(var);
11481  vbdcoefs = SCIPvarGetVubCoefs(var);
11482  vbdconsts = SCIPvarGetVubConstants(var);
11483  nvbdvars = SCIPvarGetNVubs(var);
11484 
11485  for( b = 0; b < nvbdvars; ++b )
11486  {
11487  int idx2;
11488 
11489  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11490  assert(idx2 >= 0);
11491 
11492  if( tcliquegraph->durations[idx2] == 0 )
11493  continue;
11494 
11495  if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11496  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11497  }
11498 
11499  for( b = v+1; b < nvars; ++b )
11500  {
11501  int idx2;
11502 
11503  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11504  assert(idx2 >= 0);
11505 
11506  if( tcliquegraph->durations[idx2] == 0 )
11507  continue;
11508 
11509  /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11510  if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11511  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11512 
11513  /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11514  if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11515  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11516  }
11517  }
11518 
11519  return SCIP_OKAY;
11520 }
11521 
11522 /** compute the transitive closer of the given graph and the number of in and out arcs */
11523 static
11524 void transitiveClosure(
11525  SCIP_Bool** adjmatrix, /**< adjacent matrix */
11526  int* ninarcs, /**< array to store the number of in arcs */
11527  int* noutarcs, /**< array to store the number of out arcs */
11528  int nnodes /**< number if nodes */
11529  )
11530 {
11531  int i;
11532  int j;
11533  int k;
11534 
11535  for( i = 0; i < nnodes; ++i )
11536  {
11537  for( j = 0; j < nnodes; ++j )
11538  {
11539  if( adjmatrix[i][j] )
11540  {
11541  ninarcs[j]++;
11542  noutarcs[i]++;
11543 
11544  for( k = 0; k < nnodes; ++k )
11545  {
11546  if( adjmatrix[j][k] )
11547  adjmatrix[i][k] = TRUE;
11548  }
11549  }
11550  }
11551  }
11552 }
11553 
11554 /** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11555 static
11557  SCIP* scip, /**< SCIP data structure */
11558  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11559  SCIP_CONS** conss, /**< array of cumulative constraints */
11560  int nconss /**< number of cumulative constraints */
11561  )
11562 {
11563  int c;
11564 
11565  /* use the cumulative constraints to initialize the none overlapping graph */
11566  for( c = 0; c < nconss; ++c )
11567  {
11568  SCIP_CONSDATA* consdata;
11569  SCIP_VAR** vars;
11570  int* demands;
11571  int capacity;
11572  int nvars;
11573  int i;
11574 
11575  consdata = SCIPconsGetData(conss[c]);
11576  assert(consdata != NULL);
11577 
11578  vars = consdata->vars;
11579  demands = consdata->demands;
11580 
11581  nvars = consdata->nvars;
11582  capacity = consdata->capacity;
11583 
11584  SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11585 
11586  /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11587  for( i = 0; i < nvars; ++i )
11588  {
11589  int idx1;
11590  int j;
11591 
11592  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11593  assert(idx1 >= 0);
11594 
11595  if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11596  continue;
11597 
11598  for( j = i+1; j < nvars; ++j )
11599  {
11600  assert(consdata->durations[j] > 0);
11601 
11602  if( demands[i] + demands[j] > capacity )
11603  {
11604  int idx2;
11605  int est1;
11606  int est2;
11607  int lct1;
11608  int lct2;
11609 
11610  /* check if the effective horizon is large enough */
11611  est1 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[i]));
11612  est2 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[j]));
11613 
11614  /* at least one of the jobs needs to start at hmin or later */
11615  if( est1 < consdata->hmin && est2 < consdata->hmin )
11616  continue;
11617 
11618  lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11619  lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11620 
11621  /* at least one of the jobs needs to finish not later then hmin */
11622  if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11623  continue;
11624 
11625  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11626  assert(idx2 >= 0);
11627  assert(idx1 != idx2);
11628 
11629  if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11630  continue;
11631 
11632  SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11633 
11634  assert(tcliquegraph->durations[idx1] > 0);
11635  assert(tcliquegraph->durations[idx2] > 0);
11636 
11637  tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11638  tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11639 
11640  }
11641  }
11642  }
11643  }
11644 
11645  return SCIP_OKAY;
11646 }
11647 
11648 /** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11649  * of jobs cannot run in parallel
11650  */
11651 static
11653  SCIP* scip, /**< SCIP data structure */
11654  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11655  SCIP_CONS** conss, /**< array of cumulative constraints */
11656  int nconss /**< number of cumulative constraints */
11657  )
11658 {
11659  assert(scip != NULL);
11660  assert(tcliquegraph != NULL);
11661 
11662  /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11663  SCIP_CALL( projectVbd(scip, tcliquegraph) );
11664 
11665  /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11666  transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11667 
11668  /* constraints non-overlapping graph */
11669  SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11670 
11671  return SCIP_OKAY;
11672 }
11673 
11674 /** create cumulative constraint from conflict set */
11675 static
11677  SCIP* scip, /**< SCIP data structure */
11678  const char* name, /**< constraint name */
11679  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11680  int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11681  int ncliquenodes /**< number of nodes in the clique */
11682  )
11683 {
11684  SCIP_CONS* cons;
11685  SCIP_VAR** vars;
11686  int* durations;
11687  int* demands;
11688  int v;
11689 
11690  SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11691  SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11692  SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11693 
11694  SCIPsortInt(cliquenodes, ncliquenodes);
11695 
11696  /* collect variables, durations, and demands */
11697  for( v = 0; v < ncliquenodes; ++v )
11698  {
11699  durations[v] = tcliquegraph->durations[cliquenodes[v]];
11700  assert(durations[v] > 0);
11701  demands[v] = 1;
11702  vars[v] = tcliquegraph->vars[cliquenodes[v]];
11703  }
11704 
11705  /* create (unary) cumulative constraint */
11706  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11708 
11709  SCIP_CALL( SCIPaddCons(scip, cons) );
11710  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11711 
11712  /* free buffers */
11713  SCIPfreeBufferArray(scip, &demands);
11714  SCIPfreeBufferArray(scip, &durations);
11715  SCIPfreeBufferArray(scip, &vars);
11716 
11717  return SCIP_OKAY;
11718 }
11719 
11720 /** search for cumulative constrainst */
11721 static
11723  SCIP* scip, /**< SCIP data structure */
11724  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11725  int* naddconss /**< pointer to store the number of added constraints */
11726  )
11727 {
11728  TCLIQUE_STATUS tcliquestatus;
11729  SCIP_Bool* precedencerow;
11730  SCIP_Bool* precedencecol;
11731  SCIP_Bool* demandrow;
11732  SCIP_Bool* demandcol;
11733  SCIP_HASHTABLE* covered;
11734  int* cliquenodes;
11735  int ncliquenodes;
11736  int cliqueweight;
11737  int ntreenodes;
11738  int nnodes;
11739  int nconss;
11740  int v;
11741 
11742  nnodes = tcliquegraph->nnodes;
11743  nconss = 0;
11744 
11745  /* initialize the weight of each job with its duration */
11746  for( v = 0; v < nnodes; ++v )
11747  {
11748  tcliquegraph->weights[v] = tcliquegraph->durations[v];
11749  }
11750 
11751  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11752  SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11753  SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11754  SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11755  SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11756 
11757  /* create a hash table to store all start time variables which are already covered by at least one clique */
11758  SCIP_CALL( SCIPhashtableCreate(&covered, SCIPblkmem(scip), nnodes,
11759  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11760 
11761  /* for each variables/job we are ... */
11762  for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11763  {
11764  char name[SCIP_MAXSTRLEN];
11765  int c;
11766 
11767  /* jobs with zero durations are skipped */
11768  if( tcliquegraph->durations[v] == 0 )
11769  continue;
11770 
11771  /* check if the start time variable is already covered by at least one clique */
11772  if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11773  continue;
11774 
11775  SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11776 
11777  /* temporarily remove the connection via the precedence graph */
11778  for( c = 0; c < nnodes; ++c )
11779  {
11780  precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11781  precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11782 
11783  demandrow[c] = tcliquegraph->demandmatrix[v][c];
11784  demandcol[c] = tcliquegraph->demandmatrix[c][v];
11785 
11786 #if 0
11787  if( precedencerow[c] || precedencecol[c] )
11788  {
11789  tcliquegraph->demandmatrix[v][c] = FALSE;
11790  tcliquegraph->demandmatrix[c][v] = FALSE;
11791  }
11792 #endif
11793 
11794  tcliquegraph->precedencematrix[c][v] = FALSE;
11795  tcliquegraph->precedencematrix[v][c] = FALSE;
11796  }
11797 
11798  /* find (heuristically) maximum cliques which includes node v */
11799  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11800  tcliquegraph, tcliqueNewsolClique, NULL,
11801  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11802  10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11803 
11804  SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11805 
11806  if( ncliquenodes == 1 )
11807  continue;
11808 
11809  /* construct constraint name */
11810  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11811 
11812  SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11813  nconss++;
11814 
11815  /* all start time variable to covered hash table */
11816  for( c = 0; c < ncliquenodes; ++c )
11817  {
11818  SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11819  }
11820 
11821  /* copy the precedence relations back */
11822  for( c = 0; c < nnodes; ++c )
11823  {
11824  tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11825  tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11826 
11827  tcliquegraph->demandmatrix[v][c] = demandrow[c];
11828  tcliquegraph->demandmatrix[c][v] = demandcol[c];
11829  }
11830  }
11831 
11832  SCIPhashtableFree(&covered);
11833 
11834  SCIPfreeBufferArray(scip, &demandcol);
11835  SCIPfreeBufferArray(scip, &demandrow);
11836  SCIPfreeBufferArray(scip, &precedencecol);
11837  SCIPfreeBufferArray(scip, &precedencerow);
11838  SCIPfreeBufferArray(scip, &cliquenodes);
11839 
11840  (*naddconss) += nconss;
11841 
11842  /* for the statistic we count the number added disjunctive constraints */
11843  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11844 
11845  return SCIP_OKAY;
11846 }
11847 
11848 /** create precedence constraint (as variable bound constraint */
11849 static
11851  SCIP* scip, /**< SCIP data structure */
11852  const char* name, /**< constraint name */
11853  SCIP_VAR* var, /**< variable x that has variable bound */
11854  SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11855  int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11856  )
11857 {
11858  SCIP_CONS* cons;
11859 
11860  /* create variable bound constraint */
11861  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11863 
11864  SCIPdebugPrintCons(scip, cons, NULL);
11865 
11866  /* add constraint to problem and release it */
11867  SCIP_CALL( SCIPaddCons(scip, cons) );
11868  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11869 
11870  return SCIP_OKAY;
11871 }
11872 
11873 /** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11874 static
11876  SCIP* scip, /**< SCIP data structure */
11877  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11878  int source, /**< index of the source node */
11879  int sink, /**< index of the sink node */
11880  int* naddconss /**< pointer to store the number of added constraints */
11881  )
11882 {
11883  TCLIQUE_WEIGHT cliqueweight;
11884  TCLIQUE_STATUS tcliquestatus;
11885  SCIP_VAR** vars;
11886  int* cliquenodes;
11887  int nnodes;
11888  int lct;
11889  int est;
11890  int i;
11891 
11892  int ntreenodes;
11893  int ncliquenodes;
11894 
11895  /* check if source and sink are connencted */
11896  if( !tcliquegraph->precedencematrix[source][sink] )
11897  return SCIP_OKAY;
11898 
11899  nnodes = tcliquegraph->nnodes;
11900  vars = tcliquegraph->vars;
11901 
11902  /* reset the weights to zero */
11903  BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11904 
11905  /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11906  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11907  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[sink]));
11908 
11909  /* weight all jobs which run for sure between source and sink with their duration */
11910  for( i = 0; i < nnodes; ++i )
11911  {
11912  SCIP_VAR* var;
11913  int duration;
11914 
11915  var = vars[i];
11916  assert(var != NULL);
11917 
11918  duration = tcliquegraph->durations[i];
11919 
11920  if( i == source || i == sink )
11921  {
11922  /* source and sink are not weighted */
11923  tcliquegraph->weights[i] = 0;
11924  }
11925  else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11926  {
11927  /* job i runs after source and before sink */
11928  tcliquegraph->weights[i] = duration;
11929  }
11930  else if( lct <= SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var))
11931  && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11932  {
11933  /* job i run in between due the bounds of the start time variables */
11934  tcliquegraph->weights[i] = duration;
11935  }
11936  else
11937  tcliquegraph->weights[i] = 0;
11938  }
11939 
11940  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11941 
11942  /* find (heuristically) maximum cliques */
11943  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11944  tcliquegraph, tcliqueNewsolClique, NULL,
11945  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11946  10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11947 
11948  if( ncliquenodes > 1 )
11949  {
11950  char name[SCIP_MAXSTRLEN];
11951  int distance;
11952 
11953  /* construct constraint name */
11954  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11955 
11956  /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11957  * duration of the source job
11958  */
11959  distance = cliqueweight + tcliquegraph->durations[source];
11960 
11961  SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11962  (*naddconss)++;
11963  }
11964 
11965  SCIPfreeBufferArray(scip, &cliquenodes);
11966 
11967  return SCIP_OKAY;
11968 }
11969 
11970 /** search for precedence constraints
11971  *
11972  * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
11973  * corresponding two jobs
11974  */
11975 static
11977  SCIP* scip, /**< SCIP data structure */
11978  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11979  int* naddconss /**< pointer to store the number of added constraints */
11980  )
11981 {
11982  int* sources;
11983  int* sinks;
11984  int nconss;
11985  int nnodes;
11986  int nsources;
11987  int nsinks;
11988  int i;
11989 
11990  nnodes = tcliquegraph->nnodes;
11991  nconss = 0;
11992 
11993  nsources = 0;
11994  nsinks = 0;
11995 
11996  SCIP_CALL( SCIPallocBufferArray(scip, &sources, nnodes) );
11997  SCIP_CALL( SCIPallocBufferArray(scip, &sinks, nnodes) );
11998 
11999  /* first collect all sources and sinks */
12000  for( i = 0; i < nnodes; ++i )
12001  {
12002  if( tcliquegraph->ninarcs[i] == 0 )
12003  {
12004  sources[nsources] = i;
12005  nsources++;
12006  }
12007 
12008  if( tcliquegraph->ninarcs[i] == 0 )
12009  {
12010  sinks[nsinks] = i;
12011  nsinks++;
12012  }
12013  }
12014 
12015  /* compute for each node a minimum distance to each sources and each sink */
12016  for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
12017  {
12018  int j;
12019 
12020  for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
12021  {
12022  SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
12023  }
12024 
12025  for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
12026  {
12027  SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
12028  }
12029  }
12030 
12031  (*naddconss) += nconss;
12032 
12033  /* for the statistic we count the number added variable constraints */
12034  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
12035 
12036  SCIPfreeBufferArray(scip, &sinks);
12037  SCIPfreeBufferArray(scip, &sources);
12038 
12039  return SCIP_OKAY;
12040 }
12041 
12042 /** initialize the assumed durations for each variable */
12043 static
12045  SCIP* scip, /**< SCIP data structure */
12046  TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
12047  SCIP_CONS** conss, /**< cumulative constraints */
12048  int nconss /**< number of cumulative constraints */
12049  )
12050 {
12051  int c;
12052 
12053  /* use the cumulative structure to define the duration we are using for each job */
12054  for( c = 0; c < nconss; ++c )
12055  {
12056  SCIP_CONSDATA* consdata;
12057  SCIP_VAR** vars;
12058  int nvars;
12059  int v;
12060 
12061  consdata = SCIPconsGetData(conss[c]);
12062  assert(consdata != NULL);
12063 
12064  vars = consdata->vars;
12065  nvars = consdata->nvars;
12066 
12067  for( v = 0; v < nvars; ++v )
12068  {
12069  int idx;
12070 
12071  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12072  assert(idx >= 0);
12073 
12074  /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12075  * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12076  * general this is not the case. Therefore, the question would be which duration should be used?
12077  */
12078  tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12079  assert(tcliquegraph->durations[idx] > 0);
12080  }
12081  }
12082 
12083  return SCIP_OKAY;
12084 }
12085 
12086 /** create tclique graph */
12087 static
12089  SCIP* scip, /**< SCIP data structure */
12090  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12091  )
12092 {
12093  SCIP_VAR** vars;
12094  SCIP_HASHMAP* varmap;
12095  SCIP_Bool** precedencematrix;
12096  SCIP_Bool** demandmatrix;
12097  int* ninarcs;
12098  int* noutarcs;
12099  int* durations;
12100  int* weights;
12101  int nvars;
12102  int v;
12103 
12104  vars = SCIPgetVars(scip);
12105  nvars = SCIPgetNVars(scip);
12106 
12107  /* allocate memory for the tclique graph data structure */
12108  SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12109 
12110  /* create the variable mapping hash map */
12111  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
12112 
12113  /* each active variables get a node in the graph */
12114  SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12115 
12116  /* allocate memory for the projected variables bound graph and the none overlapping graph */
12117  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12118  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12119 
12120  /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12121  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12122  BMSclearMemoryArray(weights, nvars);
12123 
12124  /* array to store the number of in arc of the precedence graph */
12125  SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12126  BMSclearMemoryArray(ninarcs, nvars);
12127 
12128  /* array to store the number of out arc of the precedence graph */
12129  SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12130  BMSclearMemoryArray(noutarcs, nvars);
12131 
12132  /* array to store the used duration for each node */
12133  SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12134  BMSclearMemoryArray(durations, nvars);
12135 
12136  for( v = 0; v < nvars; ++v )
12137  {
12138  SCIP_VAR* var;
12139 
12140  var = vars[v];
12141  assert(var != NULL);
12142 
12143  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12144  BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12145 
12146  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12147  BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12148 
12149  /* insert all active variables into the garph */
12150  assert(SCIPvarGetProbindex(var) == v);
12151  SCIP_CALL( SCIPhashmapInsert(varmap, (void*)var, (void*)(size_t)v) ); /*lint !e571*/
12152  }
12153 
12154  (*tcliquegraph)->nnodes = nvars;
12155  (*tcliquegraph)->varmap = varmap;
12156  (*tcliquegraph)->precedencematrix = precedencematrix;
12157  (*tcliquegraph)->demandmatrix = demandmatrix;
12158  (*tcliquegraph)->weights = weights;
12159  (*tcliquegraph)->ninarcs = ninarcs;
12160  (*tcliquegraph)->noutarcs = noutarcs;
12161  (*tcliquegraph)->durations = durations;
12162  (*tcliquegraph)->size = nvars;
12163 
12164  return SCIP_OKAY;
12165 }
12166 
12167 /** frees the tclique graph */
12168 static
12169 void freeTcliqueGraph(
12170  SCIP* scip, /**< SCIP data structure */
12171  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12172  )
12173 {
12174  int v;
12175 
12176  for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12177  {
12178  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12179  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12180  }
12181 
12182  SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12183  SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12184  SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12185  SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12186  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12187  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12188  SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12189  SCIPhashmapFree(&(*tcliquegraph)->varmap);
12190 
12191  SCIPfreeBuffer(scip, tcliquegraph);
12192 }
12193 
12194 /** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12195  * constrains (disjunctive constraint)
12196  */
12197 static
12199  SCIP* scip, /**< SCIP data structure */
12200  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12201  SCIP_CONS** conss, /**< array of cumulative constraints */
12202  int nconss, /**< number of cumulative constraints */
12203  int* naddconss /**< pointer to store the number of added constraints */
12204  )
12205 {
12206  TCLIQUE_GRAPH* tcliquegraph;
12207 
12208  /* create tclique graph */
12209  SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12210 
12211  /* define for each job a duration */
12212  SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12213 
12214  /* constuct incompatibility graph */
12215  SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12216 
12217  /* search for new precedence constraints */
12218  if( conshdlrdata->detectvarbounds )
12219  {
12220  SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12221  }
12222 
12223  /* search for new cumulative constraints */
12224  if( conshdlrdata->detectdisjunctive )
12225  {
12226  SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12227  }
12228 
12229  /* free tclique graph data structure */
12230  freeTcliqueGraph(scip, &tcliquegraph);
12231 
12232  return SCIP_OKAY;
12233 }
12234 
12235 /** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12236 static
12238  SCIP_CONSDATA* consdata /**< cumulative constraint data */
12239  )
12240 {
12241  SCIP_VAR** vars;
12242  int nvars;
12243  int v;
12244 
12245  if( consdata->validsignature )
12246  return;
12247 
12248  vars = consdata->vars;
12249  nvars = consdata->nvars;
12250 
12251  for( v = 0; v < nvars; ++v )
12252  {
12253  consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12254  }
12255 
12256  consdata->validsignature = TRUE;
12257 }
12258 
12259 /** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12260 static
12261 SCIP_DECL_SORTINDCOMP(consdataCompVar)
12262 { /*lint --e{715}*/
12263  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12264 
12265  assert(consdata != NULL);
12266  assert(0 <= ind1 && ind1 < consdata->nvars);
12267  assert(0 <= ind2 && ind2 < consdata->nvars);
12268 
12269  return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12270 }
12271 
12272 /** run a pairwise comparison */
12273 static
12275  SCIP* scip, /**< SCIP data structure */
12276  SCIP_CONS** conss, /**< array of cumulative constraints */
12277  int nconss, /**< number of cumulative constraints */
12278  int* ndelconss /**< pointer to store the number of deletedconstraints */
12279  )
12280 {
12281  int i;
12282  int j;
12283 
12284  for( i = 0; i < nconss; ++i )
12285  {
12286  SCIP_CONSDATA* consdata0;
12287  SCIP_CONS* cons0;
12288 
12289  cons0 = conss[i];
12290  assert(cons0 != NULL);
12291 
12292  consdata0 = SCIPconsGetData(cons0);
12293  assert(consdata0 != NULL);
12294 
12295  consdataCalcSignature(consdata0);
12296  assert(consdata0->validsignature);
12297 
12298  for( j = i+1; j < nconss; ++j )
12299  {
12300  SCIP_CONSDATA* consdata1;
12301  SCIP_CONS* cons1;
12302 
12303  cons1 = conss[j];
12304  assert(cons1 != NULL);
12305 
12306  consdata1 = SCIPconsGetData(cons1);
12307  assert(consdata1 != NULL);
12308 
12309  if( consdata0->capacity != consdata1->capacity )
12310  continue;
12311 
12312  consdataCalcSignature(consdata1);
12313  assert(consdata1->validsignature);
12314 
12315  if( (consdata1->signature & (~consdata0->signature)) == 0 )
12316  {
12317  SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12318  SCIPswapPointers((void**)&cons0, (void**)&cons1);
12319  assert((consdata0->signature & (~consdata1->signature)) == 0);
12320  }
12321 
12322  if( (consdata0->signature & (~consdata1->signature)) == 0 )
12323  {
12324  int* perm0;
12325  int* perm1;
12326  int v0;
12327  int v1;
12328 
12329  if( consdata0->nvars > consdata1->nvars )
12330  continue;
12331 
12332  if( consdata0->hmin < consdata1->hmin )
12333  continue;
12334 
12335  if( consdata0->hmax > consdata1->hmax )
12336  continue;
12337 
12338  SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12339  SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12340 
12341  /* call sorting method */
12342  SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12343  SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12344 
12345  for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12346  {
12347  SCIP_VAR* var0;
12348  SCIP_VAR* var1;
12349  int idx0;
12350  int idx1;
12351  int comp;
12352 
12353  idx0 = perm0[v0];
12354  idx1 = perm1[v1];
12355 
12356  var0 = consdata0->vars[idx0];
12357 
12358  var1 = consdata1->vars[idx1];
12359 
12360  comp = SCIPvarCompare(var0, var1);
12361 
12362  if( comp == 0 )
12363  {
12364  int duration0;
12365  int duration1;
12366  int demand0;
12367  int demand1;
12368 
12369  demand0 = consdata0->demands[idx0];
12370  duration0 = consdata0->durations[idx0];
12371 
12372  demand1 = consdata1->demands[idx1];
12373  duration1 = consdata1->durations[idx1];
12374 
12375  if( demand0 != demand1 )
12376  break;
12377 
12378  if( duration0 != duration1 )
12379  break;
12380 
12381  v0++;
12382  v1++;
12383  }
12384  else if( comp > 0 )
12385  v1++;
12386  else
12387  break;
12388  }
12389 
12390  if( v0 == consdata0->nvars )
12391  {
12392  if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12393  {
12394  initializeLocks(consdata1, TRUE);
12395  }
12396 
12397  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12398 
12399  SCIP_CALL( SCIPdelCons(scip, cons0) );
12400  (*ndelconss)++;
12401  }
12402 
12403  SCIPfreeBufferArray(scip, &perm1);
12404  SCIPfreeBufferArray(scip, &perm0);
12405  }
12406  }
12407  }
12408 
12409  return SCIP_OKAY;
12410 }
12411 
12412 /** strengthen the variable bounds using the cumulative condition */
12413 static
12415  SCIP* scip, /**< SCIP data structure */
12416  SCIP_CONS* cons, /**< constraint to propagate */
12417  int* nchgbds, /**< pointer to store the number of changed bounds */
12418  int* naddconss /**< pointer to store the number of added constraints */
12419  )
12420 {
12421  SCIP_CONSDATA* consdata;
12422  SCIP_VAR** vars;
12423  int* durations;
12424  int* demands;
12425  int capacity;
12426  int nvars;
12427  int nconss;
12428  int i;
12429 
12430  consdata = SCIPconsGetData(cons);
12431  assert(consdata != NULL);
12432 
12433  /* check if the variable bounds got already strengthen by the cumulative constraint */
12434  if( consdata->varbounds )
12435  return SCIP_OKAY;
12436 
12437  vars = consdata->vars;
12438  durations = consdata->durations;
12439  demands = consdata->demands;
12440  capacity = consdata->capacity;
12441  nvars = consdata->nvars;
12442 
12443  nconss = 0;
12444 
12445  for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12446  {
12447  SCIP_VAR** vbdvars;
12448  SCIP_VAR* var;
12449  SCIP_Real* vbdcoefs;
12450  SCIP_Real* vbdconsts;
12451  int nvbdvars;
12452  int b;
12453  int j;
12454 
12455  var = consdata->vars[i];
12456  assert(var != NULL);
12457 
12458  vbdvars = SCIPvarGetVlbVars(var);
12459  vbdcoefs = SCIPvarGetVlbCoefs(var);
12460  vbdconsts = SCIPvarGetVlbConstants(var);
12461  nvbdvars = SCIPvarGetNVlbs(var);
12462 
12463  for( b = 0; b < nvbdvars; ++b )
12464  {
12465  if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12466  {
12467  if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12468  {
12469  for( j = 0; j < nvars; ++j )
12470  {
12471  if( vars[j] == vbdvars[b] )
12472  break;
12473  }
12474  if( j == nvars )
12475  continue;
12476 
12477  if( demands[i] + demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12478  {
12479  SCIP_Bool infeasible;
12480  char name[SCIP_MAXSTRLEN];
12481  int nlocalbdchgs;
12482 
12483  SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12484 
12485  /* construct constraint name */
12486  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12487 
12488  SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12489  nconss++;
12490 
12491  SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12492  assert(!infeasible);
12493 
12494  (*nchgbds) += nlocalbdchgs;
12495  }
12496  }
12497  }
12498  }
12499  }
12500 
12501  (*naddconss) += nconss;
12502 
12503  consdata->varbounds = TRUE;
12504 
12505  return SCIP_OKAY;
12506 }
12507 
12508 /** helper function to enforce constraints */
12509 static
12511  SCIP* scip, /**< SCIP data structure */
12512  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
12513  SCIP_CONS** conss, /**< constraints to process */
12514  int nconss, /**< number of constraints */
12515  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
12516  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
12517  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
12518  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
12519  )
12520 {
12521  SCIP_CONSHDLRDATA* conshdlrdata;
12522 
12523  assert(conshdlr != NULL);
12524  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12525  assert(nconss == 0 || conss != NULL);
12526  assert(result != NULL);
12527 
12528  if( solinfeasible )
12529  {
12530  *result = SCIP_INFEASIBLE;
12531  return SCIP_OKAY;
12532  }
12533 
12534  SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12535  sol == NULL ? "LP" : "relaxation");
12536 
12537  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12538  assert(conshdlrdata != NULL);
12539 
12540  (*result) = SCIP_FEASIBLE;
12541 
12542  if( conshdlrdata->usebinvars )
12543  {
12544  SCIP_Bool separated;
12545  SCIP_Bool cutoff;
12546  int c;
12547 
12548  separated = FALSE;
12549 
12550  /* first check if a constraints is violated */
12551  for( c = 0; c < nusefulconss; ++c )
12552  {
12553  SCIP_CONS* cons;
12554  SCIP_Bool violated;
12555 
12556  cons = conss[c];
12557  assert(cons != NULL);
12558 
12559  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12560 
12561  if( !violated )
12562  continue;
12563 
12564  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12565  if ( cutoff )
12566  {
12567  *result = SCIP_CUTOFF;
12568  return SCIP_OKAY;
12569  }
12570  }
12571 
12572  for( ; c < nconss && !separated; ++c )
12573  {
12574  SCIP_CONS* cons;
12575  SCIP_Bool violated;
12576 
12577  cons = conss[c];
12578  assert(cons != NULL);
12579 
12580  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12581 
12582  if( !violated )
12583  continue;
12584 
12585  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12586  if ( cutoff )
12587  {
12588  *result = SCIP_CUTOFF;
12589  return SCIP_OKAY;
12590  }
12591  }
12592 
12593  if( separated )
12594  (*result) = SCIP_SEPARATED;
12595  }
12596  else
12597  {
12598  SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12599  }
12600 
12601  return SCIP_OKAY;
12602 }
12603 
12604 /**@} */
12605 
12606 
12607 /**@name Callback methods of constraint handler
12608  *
12609  * @{
12610  */
12611 
12612 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12613 static
12614 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12615 { /*lint --e{715}*/
12616  assert(scip != NULL);
12617  assert(conshdlr != NULL);
12618  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12619 
12620  /* call inclusion method of constraint handler */
12622 
12624 
12625  *valid = TRUE;
12626 
12627  return SCIP_OKAY;
12628 }
12629 
12630 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12631 static
12632 SCIP_DECL_CONSFREE(consFreeCumulative)
12633 { /*lint --e{715}*/
12634  SCIP_CONSHDLRDATA* conshdlrdata;
12635 
12636  assert(conshdlr != NULL);
12637  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12638 
12639  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12640  assert(conshdlrdata != NULL);
12641 
12642 #ifdef SCIP_STATISTIC
12643  if( !conshdlrdata->iscopy )
12644  {
12645  /* statisitc output if SCIP_STATISTIC is defined */
12646  SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12647  conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12648  SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12649  conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12650  SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12651  conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12652  }
12653 #endif
12654 
12655  conshdlrdataFree(scip, &conshdlrdata);
12656 
12657  SCIPconshdlrSetData(conshdlr, NULL);
12658 
12659  return SCIP_OKAY;
12660 }
12661 
12662 
12663 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12664 static
12665 SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12666 { /*lint --e{715}*/
12667  SCIP_CONSHDLRDATA* conshdlrdata;
12668  int c;
12669 
12670  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12671  assert(conshdlrdata != NULL);
12672 
12673  conshdlrdata->detectedredundant = FALSE;
12674 
12675  for( c = 0; c < nconss; ++c )
12676  {
12677  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12678  * hmax)
12679  */
12680  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12681  }
12682 
12683  return SCIP_OKAY;
12684 }
12685 
12686 
12687 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12688 #ifdef SCIP_STATISTIC
12689 static
12690 SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12691 { /*lint --e{715}*/
12692  SCIP_CONSHDLRDATA* conshdlrdata;
12693  int c;
12694 
12695  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12696  assert(conshdlrdata != NULL);
12697 
12698  for( c = 0; c < nconss; ++c )
12699  {
12700  SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12701 
12702 #if 0
12703  SCIP_CALL( SCIPvisualizeConsCumulative(scip, conss[c]) );
12704 #endif
12705  }
12706 
12707  if( !conshdlrdata->iscopy )
12708  {
12709  SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12710  SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12711  SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12712  SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12713  SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12714  SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12715  SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12716  SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12717  SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12718  }
12719 
12720  return SCIP_OKAY;
12721 }
12722 #endif
12723 
12724 
12725 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12726 static
12727 SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12728 { /*lint --e{715}*/
12729  SCIP_CONSDATA* consdata;
12730  int c;
12731 
12732  assert(conshdlr != NULL);
12733  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12734 
12735  /* release the rows of all constraints */
12736  for( c = 0; c < nconss; ++c )
12737  {
12738  consdata = SCIPconsGetData(conss[c]);
12739  assert(consdata != NULL);
12740 
12741  /* free rows */
12742  SCIP_CALL( consdataFreeRows(scip, &consdata) );
12743  }
12744 
12745  return SCIP_OKAY;
12746 }
12747 
12748 /** frees specific constraint data */
12749 static
12750 SCIP_DECL_CONSDELETE(consDeleteCumulative)
12751 { /*lint --e{715}*/
12752  assert(conshdlr != NULL);
12753  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12754  assert(consdata != NULL );
12755  assert(*consdata != NULL );
12756 
12757  /* if constraint belongs to transformed problem space, drop bound change events on variables */
12758  if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12759  {
12760  SCIP_CONSHDLRDATA* conshdlrdata;
12761 
12762  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12763  assert(conshdlrdata != NULL);
12764 
12765  SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12766  }
12767 
12768  /* free cumulative constraint data */
12769  SCIP_CALL( consdataFree(scip, consdata) );
12770 
12771  return SCIP_OKAY;
12772 }
12773 
12774 /** transforms constraint data into data belonging to the transformed problem */
12775 static
12776 SCIP_DECL_CONSTRANS(consTransCumulative)
12777 { /*lint --e{715}*/
12778  SCIP_CONSHDLRDATA* conshdlrdata;
12779  SCIP_CONSDATA* sourcedata;
12780  SCIP_CONSDATA* targetdata;
12781 
12782  assert(conshdlr != NULL);
12783  assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
12784  assert(sourcecons != NULL);
12785  assert(targetcons != NULL);
12786 
12787  sourcedata = SCIPconsGetData(sourcecons);
12788  assert(sourcedata != NULL);
12789  assert(sourcedata->demandrows == NULL);
12790 
12791  SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12792 
12793  /* get event handler */
12794  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12795  assert(conshdlrdata != NULL);
12796  assert(conshdlrdata->eventhdlr != NULL);
12797 
12798  /* create constraint data for target constraint */
12799  SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12800  sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12801  sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12802 
12803  /* create target constraint */
12804  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12805  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12806  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12807  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12808  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12809 
12810  /* catch bound change events of variables */
12811  SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12812 
12813  return SCIP_OKAY;
12814 }
12815 
12816 /** LP initialization method of constraint handler */
12817 static
12818 SCIP_DECL_CONSINITLP(consInitlpCumulative)
12820  SCIP_CONSHDLRDATA* conshdlrdata;
12821  int c;
12822 
12823  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12824  assert(conshdlr != NULL);
12825  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12826  assert(conshdlrdata != NULL);
12827 
12828  *infeasible = FALSE;
12829 
12830  SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12831 
12832  if( conshdlrdata->usebinvars )
12833  {
12834  /* add rows to LP */
12835  for( c = 0; c < nconss && !(*infeasible); ++c )
12836  {
12837  assert(SCIPconsIsInitial(conss[c]));
12838  SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12839 
12840  if( conshdlrdata->cutsasconss )
12841  {
12842  SCIP_CALL( SCIPrestartSolve(scip) );
12843  }
12844  }
12845  }
12846 
12847  /**@todo if we want to use only the integer variables; only these will be in cuts
12848  * create some initial cuts, currently these are only separated */
12849 
12850  return SCIP_OKAY;
12851 }
12852 
12853 /** separation method of constraint handler for LP solutions */
12854 static
12855 SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12857  SCIP_CONSHDLRDATA* conshdlrdata;
12858  SCIP_Bool cutoff;
12859  SCIP_Bool separated;
12860  int c;
12861 
12862  SCIPdebugMsg(scip, "consSepalpCumulative\n");
12863 
12864  assert(conshdlr != NULL);
12865  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12866  assert(nconss == 0 || conss != NULL);
12867  assert(result != NULL);
12868  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12869  assert(conshdlrdata != NULL);
12870 
12871  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12872 
12873  cutoff = FALSE;
12874  separated = FALSE;
12875  (*result) = SCIP_DIDNOTRUN;
12876 
12877  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12878  return SCIP_OKAY;
12879 
12880  (*result) = SCIP_DIDNOTFIND;
12881 
12882  if( conshdlrdata->usebinvars )
12883  {
12884  /* check all useful cumulative constraints for feasibility */
12885  for( c = 0; c < nusefulconss && !cutoff; ++c )
12886  {
12887  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12888  }
12889 
12890  if( !cutoff && conshdlrdata->usecovercuts )
12891  {
12892  for( c = 0; c < nusefulconss; ++c )
12893  {
12894  SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12895  }
12896  }
12897  }
12898 
12899  if( conshdlrdata->sepaold )
12900  {
12901  /* separate cuts containing only integer variables */
12902  for( c = 0; c < nusefulconss; ++c )
12903  {
12904  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated) );
12905  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated) );
12906  }
12907  }
12908 
12909  if( cutoff )
12910  *result = SCIP_CUTOFF;
12911  else if( separated )
12912  *result = SCIP_SEPARATED;
12913 
12914  return SCIP_OKAY;
12915 }
12916 
12917 /** separation method of constraint handler for arbitrary primal solutions */
12918 static
12919 SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12920 { /*lint --e{715}*/
12921  SCIP_CONSHDLRDATA* conshdlrdata;
12922  SCIP_Bool cutoff;
12923  SCIP_Bool separated;
12924  int c;
12925 
12926  assert(conshdlr != NULL);
12927  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12928  assert(nconss == 0 || conss != NULL);
12929  assert(result != NULL);
12930 
12931  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12932  assert(conshdlrdata != NULL);
12933 
12934  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12935  return SCIP_OKAY;
12936 
12937  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12938 
12939  cutoff = FALSE;
12940  separated = FALSE;
12941  (*result) = SCIP_DIDNOTFIND;
12942 
12943  if( conshdlrdata->usebinvars )
12944  {
12945  /* check all useful cumulative constraints for feasibility */
12946  for( c = 0; c < nusefulconss && !cutoff; ++c )
12947  {
12948  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12949  }
12950 
12951  if( !cutoff && conshdlrdata->usecovercuts )
12952  {
12953  for( c = 0; c < nusefulconss; ++c )
12954  {
12955  SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12956  }
12957  }
12958  }
12959  if( conshdlrdata->sepaold )
12960  {
12961  /* separate cuts containing only integer variables */
12962  for( c = 0; c < nusefulconss; ++c )
12963  {
12964  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated) );
12965  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated) );
12966  }
12967  }
12968 
12969  if( cutoff )
12970  *result = SCIP_CUTOFF;
12971  else if( separated )
12972  *result = SCIP_SEPARATED;
12973 
12974  return SCIP_OKAY;
12975 }
12976 
12977 /** constraint enforcing method of constraint handler for LP solutions */
12978 static
12979 SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
12980 { /*lint --e{715}*/
12981  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
12982 
12983  return SCIP_OKAY;
12984 }
12985 
12986 /** constraint enforcing method of constraint handler for relaxation solutions */
12987 static
12988 SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
12989 { /*lint --e{715}*/
12990  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
12991 
12992  return SCIP_OKAY;
12993 }
12994 
12995 /** constraint enforcing method of constraint handler for pseudo solutions */
12996 static
12997 SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
12998 { /*lint --e{715}*/
12999  SCIP_CONSHDLRDATA* conshdlrdata;
13000 
13001  SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
13002 
13003  assert(conshdlr != NULL);
13004  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13005  assert(nconss == 0 || conss != NULL);
13006  assert(result != NULL);
13007 
13008  if( objinfeasible )
13009  {
13010  *result = SCIP_DIDNOTRUN;
13011  return SCIP_OKAY;
13012  }
13013 
13014  (*result) = SCIP_FEASIBLE;
13015 
13016  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13017  assert(conshdlrdata != NULL);
13018 
13019  SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
13020 
13021  return SCIP_OKAY;
13022 }
13023 
13024 /** feasibility check method of constraint handler for integral solutions */
13025 static
13026 SCIP_DECL_CONSCHECK(consCheckCumulative)
13027 { /*lint --e{715}*/
13028  int c;
13029 
13030  assert(conshdlr != NULL);
13031  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13032  assert(nconss == 0 || conss != NULL);
13033  assert(result != NULL);
13034 
13035  *result = SCIP_FEASIBLE;
13036 
13037  SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
13038 
13039  for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
13040  {
13041  SCIP_Bool violated = FALSE;
13042 
13043  SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
13044 
13045  if( violated )
13046  *result = SCIP_INFEASIBLE;
13047  }
13048 
13049  return SCIP_OKAY;
13050 }
13051 
13052 /** domain propagation method of constraint handler */
13053 static
13054 SCIP_DECL_CONSPROP(consPropCumulative)
13055 { /*lint --e{715}*/
13056  SCIP_CONSHDLRDATA* conshdlrdata;
13057  SCIP_Bool cutoff;
13058  int nchgbds;
13059  int ndelconss;
13060  int c;
13061 #if 0
13062  int naggrvars = 0;
13063 #endif
13064 
13065  SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
13066 
13067  assert(conshdlr != NULL);
13068  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13069  assert(nconss == 0 || conss != NULL);
13070  assert(result != NULL);
13071 
13072  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13073  assert(conshdlrdata != NULL);
13074 
13075  nchgbds = 0;
13076  ndelconss = 0;
13077  cutoff = FALSE;
13078  (*result) = SCIP_DIDNOTRUN;
13079 
13080  /* propgate all useful constraints */
13081  for( c = 0; c < nusefulconss && !cutoff; ++c )
13082  {
13083  SCIP_CONS* cons;
13084 
13085  cons = conss[c];
13086  assert(cons != NULL);
13087 
13088  if( SCIPgetDepth(scip) == 0 )
13089  {
13090 #if 0
13091  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13092  &nchgbds, &naggrvars, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13093 #else
13094  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13095  &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13096 #endif
13097  if( cutoff )
13098  break;
13099 
13100  if( SCIPconsIsDeleted(cons) )
13101  continue;
13102  }
13103 
13104  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13105  }
13106 
13107  if( !cutoff && nchgbds == 0 )
13108  {
13109  /* propgate all other constraints */
13110  for( c = nusefulconss; c < nconss && !cutoff; ++c )
13111  {
13112  SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13113  }
13114  }
13115 
13116 #if 0
13117  if( !cutoff && conshdlrdata->dualpresolve && SCIPallowDualReds(scip) && nconss > 1 )
13118  {
13119  SCIP_CALL( propagateAllConss(scip, conshdlrdata, conss, nconss, TRUE, &nchgbds, &cutoff, NULL) );
13120  }
13121 #endif
13122 
13123  if( cutoff )
13124  {
13125  SCIPdebugMsg(scip, "detected infeasible\n");
13126  *result = SCIP_CUTOFF;
13127  }
13128  else if( nchgbds > 0 )
13129  {
13130  SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13131  *result = SCIP_REDUCEDDOM;
13132  }
13133  else
13134  *result = SCIP_DIDNOTFIND;
13135 
13136  return SCIP_OKAY;
13137 }
13138 
13139 /** presolving method of constraint handler */
13140 static
13141 SCIP_DECL_CONSPRESOL(consPresolCumulative)
13142 { /*lint --e{715}*/
13143  SCIP_CONSHDLRDATA* conshdlrdata;
13144  SCIP_CONS* cons;
13145  SCIP_Bool cutoff;
13146  SCIP_Bool unbounded;
13147  int oldnfixedvars;
13148  int oldnchgbds;
13149  int oldndelconss;
13150  int oldnaddconss;
13151  int oldnupgdconss;
13152  int oldnchgsides;
13153  int oldnchgcoefs;
13154  int c;
13155 
13156  assert(conshdlr != NULL);
13157  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13158  assert(scip != NULL);
13159  assert(result != NULL);
13160 
13161  SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13162 
13163  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13164  assert(conshdlrdata != NULL);
13165 
13166  *result = SCIP_DIDNOTRUN;
13167 
13168  oldnfixedvars = *nfixedvars;
13169  oldnchgbds = *nchgbds;
13170  oldnchgsides = *nchgsides;
13171  oldnchgcoefs = *nchgcoefs;
13172  oldnupgdconss = *nupgdconss;
13173  oldndelconss = *ndelconss;
13174  oldnaddconss = *naddconss;
13175  cutoff = FALSE;
13176  unbounded = FALSE;
13177 
13178  /* process constraints */
13179  for( c = 0; c < nconss && !cutoff; ++c )
13180  {
13181  cons = conss[c];
13182 
13183  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13184  * hmax)
13185  */
13186  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13187 
13188  if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13189  {
13190 #if 0
13191  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13192  nfixedvars, naggrvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13193 #else
13194  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13195  nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13196 #endif
13197 
13198  if( cutoff || unbounded )
13199  break;
13200 
13201  if( SCIPconsIsDeleted(cons) )
13202  continue;
13203  }
13204 
13205  /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13206  if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13207  {
13208  SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13209  }
13210 
13211  /* strengthen existing variable bounds using the cumulative condition */
13212  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13213  {
13214  SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13215  }
13216 
13217  /* propagate cumulative constraint */
13218  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13219  assert(checkDemands(scip, cons) || cutoff);
13220  }
13221 
13222  if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13223  {
13224  SCIP_CALL( propagateAllConss(scip, conshdlrdata, conss, nconss, FALSE,
13225  nfixedvars, &cutoff, NULL) );
13226  }
13227 
13228  /* only perform the detection of variable bounds and disjunctive constraint once */
13229  if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13230  && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13231  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13232  {
13233  /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13234  * propagation
13235  */
13236  SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13237  conshdlrdata->detectedredundant = TRUE;
13238  }
13239 
13240  if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13241  {
13242  SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13243  }
13244 
13245  SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13246  *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13247 
13248  if( cutoff )
13249  *result = SCIP_CUTOFF;
13250  else if( unbounded )
13251  *result = SCIP_UNBOUNDED;
13252  else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13253  || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13254  *result = SCIP_SUCCESS;
13255  else
13256  *result = SCIP_DIDNOTFIND;
13257 
13258  return SCIP_OKAY;
13259 }
13260 
13261 /** propagation conflict resolving method of constraint handler */
13262 static
13263 SCIP_DECL_CONSRESPROP(consRespropCumulative)
13264 { /*lint --e{715}*/
13265  SCIP_CONSHDLRDATA* conshdlrdata;
13266  SCIP_CONSDATA* consdata;
13267 
13268  assert(conshdlr != NULL);
13269  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13270  assert(scip != NULL);
13271  assert(result != NULL);
13272  assert(infervar != NULL);
13273  assert(bdchgidx != NULL);
13274 
13275  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13276  assert(conshdlrdata != NULL);
13277 
13278  /* process constraint */
13279  assert(cons != NULL);
13280 
13281  consdata = SCIPconsGetData(cons);
13282  assert(consdata != NULL);
13283 
13284  SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13285  SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13286  SCIPgetHminCumulative(scip, cons), SCIPgetHmaxCumulative(scip, cons));
13287 
13288  SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13289  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13290  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13291 
13292  return SCIP_OKAY;
13293 }
13294 
13295 /** variable rounding lock method of constraint handler */
13296 static
13297 SCIP_DECL_CONSLOCK(consLockCumulative)
13298 { /*lint --e{715}*/
13299  SCIP_CONSDATA* consdata;
13300  SCIP_VAR** vars;
13301  int v;
13302 
13303  SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13304 
13305  assert(scip != NULL);
13306  assert(cons != NULL);
13307 
13308  consdata = SCIPconsGetData(cons);
13309  assert(consdata != NULL);
13310 
13311  vars = consdata->vars;
13312  assert(vars != NULL);
13313 
13314  for( v = 0; v < consdata->nvars; ++v )
13315  {
13316  if( consdata->downlocks[v] && consdata->uplocks[v] )
13317  {
13318  /* the integer start variable should not get rounded in both direction */
13319  SCIP_CALL( SCIPaddVarLocks(scip, vars[v], nlockspos + nlocksneg, nlockspos + nlocksneg) );
13320  }
13321  else if( consdata->downlocks[v] )
13322  {
13323  SCIP_CALL( SCIPaddVarLocks(scip, vars[v], nlockspos, nlocksneg) );
13324  }
13325  else if( consdata->uplocks[v] )
13326  {
13327  SCIP_CALL( SCIPaddVarLocks(scip, vars[v], nlocksneg, nlockspos) );
13328  }
13329  }
13330 
13331  return SCIP_OKAY;
13332 }
13333 
13334 
13335 /** constraint display method of constraint handler */
13336 static
13337 SCIP_DECL_CONSPRINT(consPrintCumulative)
13338 { /*lint --e{715}*/
13339  assert(scip != NULL);
13340  assert(conshdlr != NULL);
13341  assert(cons != NULL);
13342 
13343  consdataPrint(scip, SCIPconsGetData(cons), file);
13344 
13345  return SCIP_OKAY;
13346 }
13347 
13348 /** constraint copying method of constraint handler */
13349 static
13350 SCIP_DECL_CONSCOPY(consCopyCumulative)
13351 { /*lint --e{715}*/
13352  SCIP_CONSDATA* sourceconsdata;
13353  SCIP_VAR** sourcevars;
13354  SCIP_VAR** vars;
13355  const char* consname;
13356 
13357  int nvars;
13358  int v;
13359 
13360  sourceconsdata = SCIPconsGetData(sourcecons);
13361  assert(sourceconsdata != NULL);
13362 
13363  /* get variables of the source constraint */
13364  nvars = sourceconsdata->nvars;
13365  sourcevars = sourceconsdata->vars;
13366 
13367  (*valid) = TRUE;
13368 
13369  if( nvars == 0 )
13370  return SCIP_OKAY;
13371 
13372  /* allocate buffer array */
13373  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13374 
13375  for( v = 0; v < nvars && *valid; ++v )
13376  {
13377  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13378  assert(!(*valid) || vars[v] != NULL);
13379  }
13380 
13381  /* only create the target constraint, if all variables could be copied */
13382  if( *valid )
13383  {
13384  if( name != NULL )
13385  consname = name;
13386  else
13387  consname = SCIPconsGetName(sourcecons);
13388 
13389  /* create a copy of the cumulative constraint */
13390  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13391  sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13392  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13393 
13394  /* adjust left side if the time axis if needed */
13395  if( sourceconsdata->hmin > 0 )
13396  {
13397  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13398  }
13399 
13400  /* adjust right side if the time axis if needed */
13401  if( sourceconsdata->hmax < INT_MAX )
13402  {
13403  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13404  }
13405  }
13406 
13407  /* free buffer array */
13408  SCIPfreeBufferArray(scip, &vars);
13409 
13410  return SCIP_OKAY;
13411 }
13412 
13413 
13414 /** constraint parsing method of constraint handler */
13415 static
13416 SCIP_DECL_CONSPARSE(consParseCumulative)
13417 { /*lint --e{715}*/
13418  SCIP_VAR** vars;
13419  SCIP_VAR* var;
13420  SCIP_Real value;
13421  char strvalue[SCIP_MAXSTRLEN];
13422  char* endptr;
13423  int* demands;
13424  int* durations;
13425  int capacity;
13426  int duration;
13427  int demand;
13428  int hmin;
13429  int hmax;
13430  int varssize;
13431  int nvars;
13432 
13433  SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13434 
13435  /* cutoff "cumulative" form the constraint string */
13436  SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13437  str = endptr;
13438 
13439  varssize = 100;
13440  nvars = 0;
13441 
13442  /* allocate buffer array for variables */
13443  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13444  SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13445  SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13446 
13447  do
13448  {
13449  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13450 
13451  if( var != NULL )
13452  {
13453  str = endptr;
13454 
13455  SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13456  duration = atoi(strvalue);
13457  str = endptr;
13458 
13459  SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13460  demand = atoi(strvalue);
13461  str = endptr;
13462 
13463  SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13464 
13465  vars[nvars] = var;
13466  demands[nvars] = demand;
13467  durations[nvars] = duration;
13468  nvars++;
13469  }
13470  }
13471  while( var != NULL );
13472 
13473  /* parse effective time window */
13474  SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13475  hmin = atoi(strvalue);
13476  str = endptr;
13477 
13478  if( SCIPstrToRealValue(str, &value, &endptr) )
13479  {
13480  hmax = (int)(value);
13481  str = endptr;
13482 
13483  /* parse capacity */
13484  SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13485  str = endptr;
13486  if( SCIPstrToRealValue(str, &value, &endptr) )
13487  {
13488  capacity = (int)value;
13489 
13490  /* create cumulative constraint */
13491  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13492  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13493 
13494  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13495  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13496 
13497  (*success) = TRUE;
13498  }
13499  }
13500 
13501  /* free buffer arrays */
13502  SCIPfreeBufferArray(scip, &durations);
13503  SCIPfreeBufferArray(scip, &demands);
13504  SCIPfreeBufferArray(scip, &vars);
13505 
13506  return SCIP_OKAY;
13507 }
13508 
13509 /** constraint method of constraint handler which returns the variables (if possible) */
13510 static
13511 SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13512 { /*lint --e{715}*/
13513  SCIP_CONSDATA* consdata;
13514 
13515  consdata = SCIPconsGetData(cons);
13516  assert(consdata != NULL);
13517 
13518  if( varssize < consdata->nvars )
13519  (*success) = FALSE;
13520  else
13521  {
13522  assert(vars != NULL);
13523 
13524  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13525  (*success) = TRUE;
13526  }
13527 
13528  return SCIP_OKAY;
13529 }
13530 
13531 /** constraint method of constraint handler which returns the number of variables (if possible) */
13532 static
13533 SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13534 { /*lint --e{715}*/
13535  SCIP_CONSDATA* consdata;
13536 
13537  consdata = SCIPconsGetData(cons);
13538  assert(consdata != NULL);
13539 
13540  (*nvars) = consdata->nvars;
13541  (*success) = TRUE;
13542 
13543  return SCIP_OKAY;
13544 }
13545 
13546 /**@} */
13547 
13548 /**@name Callback methods of event handler
13549  *
13550  * @{
13551  */
13552 
13553 
13554 /** execution method of event handler */
13555 static
13556 SCIP_DECL_EVENTEXEC(eventExecCumulative)
13557 { /*lint --e{715}*/
13558  SCIP_CONSDATA* consdata;
13559 
13560  assert(scip != NULL);
13561  assert(eventhdlr != NULL);
13562  assert(eventdata != NULL);
13563  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13564  assert(event != NULL);
13565 
13566  consdata = (SCIP_CONSDATA*)eventdata;
13567  assert(consdata != NULL);
13568 
13569  /* mark the constraint to be not propagated */
13570  consdata->propagated = FALSE;
13571 
13572  return SCIP_OKAY;
13573 }
13574 
13575 /**@} */
13576 
13577 /**@name Interface methods
13578  *
13579  * @{
13580  */
13581 
13582 /*
13583  * constraint specific interface methods
13584  */
13585 
13586 /** creates the handler for cumulative constraints and includes it in SCIP */
13588  SCIP* scip /**< SCIP data structure */
13589  )
13590 {
13591  SCIP_CONSHDLRDATA* conshdlrdata;
13592  SCIP_CONSHDLR* conshdlr;
13593  SCIP_EVENTHDLR* eventhdlr;
13594 
13595  /* create event handler for bound change events */
13596  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13597 
13598  /* create cumulative constraint handler data */
13599  SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13600 
13601  /* include constraint handler */
13604  consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13605  conshdlrdata) );
13606 
13607  assert(conshdlr != NULL);
13608 
13609  /* set non-fundamental callbacks via specific setter functions */
13610  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13611  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13612 #ifdef SCIP_STATISTIC
13613  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13614 #endif
13615  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13616  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13617  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13618  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13619  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13620  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13621  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13622  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13624  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13625  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropCumulative, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13627  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13628  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13630  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13631  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
13632 
13633  /* add cumulative constraint handler parameters */
13635  "constraints/" CONSHDLR_NAME "/ttinfer",
13636  "should time-table (core-times) propagator be used to infer bounds?",
13637  &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13639  "constraints/" CONSHDLR_NAME "/efcheck",
13640  "should edge-finding be used to detect an overload?",
13641  &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13643  "constraints/" CONSHDLR_NAME "/efinfer",
13644  "should edge-finding be used to infer bounds?",
13645  &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13647  "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13648  &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13650  "constraints/" CONSHDLR_NAME "/ttefcheck",
13651  "should time-table edge-finding be used to detect an overload?",
13652  &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13654  "constraints/" CONSHDLR_NAME "/ttefinfer",
13655  "should time-table edge-finding be used to infer bounds?",
13656  &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13657 
13659  "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13660  &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13662  "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13663  &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13665  "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13666  &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13668  "constraints/" CONSHDLR_NAME "/cutsasconss",
13669  "should the cumulative constraint create cuts as knapsack constraints?",
13670  &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13672  "constraints/" CONSHDLR_NAME "/sepaold",
13673  "shall old sepa algo be applied?",
13674  &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13675 
13677  "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13678  &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13679 
13680  /* presolving parameters */
13682  "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13683  &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13685  "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13686  &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13688  "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13689  &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13691  "constraints/" CONSHDLR_NAME "/presolpairwise",
13692  "should pairwise constraint comparison be performed in presolving?",
13693  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13695  "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13696  &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13697 
13699  "constraints/" CONSHDLR_NAME "/maxnodes",
13700  "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13701  &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13703  "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13704  &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13706  "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13707  &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13708 
13709  /* conflict analysis parameters */
13711  "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13712  &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13713 
13714  return SCIP_OKAY;
13715 }
13716 
13717 /** creates and captures a cumulative constraint */
13719  SCIP* scip, /**< SCIP data structure */
13720  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13721  const char* name, /**< name of constraint */
13722  int nvars, /**< number of variables (jobs) */
13723  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13724  int* durations, /**< array containing corresponding durations */
13725  int* demands, /**< array containing corresponding demands */
13726  int capacity, /**< available cumulative capacity */
13727  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13728  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13729  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13730  * Usually set to TRUE. */
13731  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13732  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13733  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13734  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13735  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13736  * Usually set to TRUE. */
13737  SCIP_Bool local, /**< is constraint only valid locally?
13738  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13739  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13740  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13741  * adds coefficients to this constraint. */
13742  SCIP_Bool dynamic, /**< is constraint subject to aging?
13743  * Usually set to FALSE. Set to TRUE for own cuts which
13744  * are seperated as constraints. */
13745  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13746  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13747  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13748  * if it may be moved to a more global node?
13749  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13750  )
13751 {
13752  SCIP_CONSHDLR* conshdlr;
13753  SCIP_CONSDATA* consdata;
13754 
13755  assert(scip != NULL);
13756 
13757  /* find the cumulative constraint handler */
13758  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13759  if( conshdlr == NULL )
13760  {
13761  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13762  return SCIP_PLUGINNOTFOUND;
13763  }
13764 
13765  SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13766 
13767  /* create constraint data */
13768  SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13769 
13770  /* create constraint */
13771  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13772  initial, separate, enforce, check, propagate,
13773  local, modifiable, dynamic, removable, stickingatnode) );
13774 
13775 
13776  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13777  {
13778  SCIP_CONSHDLRDATA* conshdlrdata;
13779 
13780  /* get event handler */
13781  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13782  assert(conshdlrdata != NULL);
13783  assert(conshdlrdata->eventhdlr != NULL);
13784 
13785  /* catch bound change events of variables */
13786  SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13787  }
13788 
13789  return SCIP_OKAY;
13790 }
13791 
13792 /** creates and captures a cumulative constraint
13793  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13794  * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13795  *
13796  * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13797  *
13798  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13799  */
13801  SCIP* scip, /**< SCIP data structure */
13802  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13803  const char* name, /**< name of constraint */
13804  int nvars, /**< number of variables (jobs) */
13805  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13806  int* durations, /**< array containing corresponding durations */
13807  int* demands, /**< array containing corresponding demands */
13808  int capacity /**< available cumulative capacity */
13809  )
13810 {
13811  assert(scip != NULL);
13812 
13813  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13814  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13815 
13816  return SCIP_OKAY;
13817 }
13818 
13819 /** set the left bound of the time axis to be considered (including hmin) */
13821  SCIP* scip, /**< SCIP data structure */
13822  SCIP_CONS* cons, /**< constraint data */
13823  int hmin /**< left bound of time axis to be considered */
13824  )
13825 {
13826  SCIP_CONSDATA* consdata;
13827  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13828  {
13829  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13830  return SCIP_INVALIDCALL;
13831  }
13832 
13833  consdata = SCIPconsGetData(cons);
13834  assert(consdata != NULL);
13835  assert(hmin >= 0);
13836  assert(hmin <= consdata->hmax);
13837 
13838  consdata->hmin = hmin;
13839 
13840  return SCIP_OKAY;
13841 }
13842 
13843 /** returns the left bound of the time axis to be considered */
13845  SCIP* scip, /**< SCIP data structure */
13846  SCIP_CONS* cons /**< constraint */
13847  )
13848 {
13849  SCIP_CONSDATA* consdata;
13850  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13851  {
13852  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13853  SCIPABORT();
13854  return 0; /*lint !e527*/
13855  }
13856 
13857  consdata = SCIPconsGetData(cons);
13858  assert(consdata != NULL);
13859 
13860  return consdata->hmin;
13861 }
13862 
13863 /** set the right bound of the time axis to be considered (not including hmax) */
13865  SCIP* scip, /**< SCIP data structure */
13866  SCIP_CONS* cons, /**< constraint data */
13867  int hmax /**< right bound of time axis to be considered */
13868  )
13869 {
13870  SCIP_CONSDATA* consdata;
13871  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13872  {
13873  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13874  SCIPABORT();
13875  return SCIP_INVALIDCALL; /*lint !e527*/
13876  }
13877 
13878  consdata = SCIPconsGetData(cons);
13879  assert(consdata != NULL);
13880  assert(hmax >= consdata->hmin);
13881 
13882  consdata->hmax = hmax;
13883 
13884  return SCIP_OKAY;
13885 }
13886 
13887 /** returns the right bound of the time axis to be considered */
13889  SCIP* scip, /**< SCIP data structure */
13890  SCIP_CONS* cons /**< constraint */
13891  )
13892 {
13893  SCIP_CONSDATA* consdata;
13894  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13895  {
13896  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13897  SCIPABORT();
13898  return 0; /*lint !e527*/
13899  }
13900 
13901  consdata = SCIPconsGetData(cons);
13902  assert(consdata != NULL);
13903 
13904  return consdata->hmax;
13905 }
13906 
13907 /** returns the activities of the cumulative constraint */
13909  SCIP* scip, /**< SCIP data structure */
13910  SCIP_CONS* cons /**< constraint data */
13911  )
13912 {
13913  SCIP_CONSDATA* consdata;
13914 
13915  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13916  {
13917  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13918  SCIPABORT();
13919  return NULL; /*lint !e527*/
13920  }
13921 
13922  consdata = SCIPconsGetData(cons);
13923  assert(consdata != NULL);
13924 
13925  return consdata->vars;
13926 }
13927 
13928 /** returns the activities of the cumulative constraint */
13930  SCIP* scip, /**< SCIP data structure */
13931  SCIP_CONS* cons /**< constraint data */
13932  )
13933 {
13934  SCIP_CONSDATA* consdata;
13935 
13936  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13937  {
13938  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13939  SCIPABORT();
13940  return -1; /*lint !e527*/
13941  }
13942 
13943  consdata = SCIPconsGetData(cons);
13944  assert(consdata != NULL);
13945 
13946  return consdata->nvars;
13947 }
13948 
13949 /** returns the capacity of the cumulative constraint */
13951  SCIP* scip, /**< SCIP data structure */
13952  SCIP_CONS* cons /**< constraint data */
13953  )
13954 {
13955  SCIP_CONSDATA* consdata;
13956 
13957  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13958  {
13959  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13960  SCIPABORT();
13961  return -1; /*lint !e527*/
13962  }
13963 
13964  consdata = SCIPconsGetData(cons);
13965  assert(consdata != NULL);
13966 
13967  return consdata->capacity;
13968 }
13969 
13970 /** returns the durations of the cumulative constraint */
13972  SCIP* scip, /**< SCIP data structure */
13973  SCIP_CONS* cons /**< constraint data */
13974  )
13975 {
13976  SCIP_CONSDATA* consdata;
13977 
13978  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13979  {
13980  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13981  SCIPABORT();
13982  return NULL; /*lint !e527*/
13983  }
13984 
13985  consdata = SCIPconsGetData(cons);
13986  assert(consdata != NULL);
13987 
13988  return consdata->durations;
13989 }
13990 
13991 /** returns the demands of the cumulative constraint */
13993  SCIP* scip, /**< SCIP data structure */
13994  SCIP_CONS* cons /**< constraint data */
13995  )
13996 {
13997  SCIP_CONSDATA* consdata;
13998 
13999  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14000  {
14001  SCIPerrorMessage("constraint is not a cumulative constraint\n");
14002  SCIPABORT();
14003  return NULL; /*lint !e527*/
14004  }
14005 
14006  consdata = SCIPconsGetData(cons);
14007  assert(consdata != NULL);
14008 
14009  return consdata->demands;
14010 }
14011 
14012 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
14013  * given solution is satisfied
14014  */
14016  SCIP* scip, /**< SCIP data structure */
14017  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
14018  int nvars, /**< number of variables (jobs) */
14019  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14020  int* durations, /**< array containing corresponding durations */
14021  int* demands, /**< array containing corresponding demands */
14022  int capacity, /**< available cumulative capacity */
14023  int hmin, /**< left bound of time axis to be considered (including hmin) */
14024  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14025  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
14026  SCIP_CONS* cons, /**< constraint which is checked */
14027  SCIP_Bool printreason /**< should the reason for the violation be printed? */
14028  )
14029 {
14030  assert(scip != NULL);
14031  assert(violated != NULL);
14032 
14033  SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
14034  violated, cons, printreason) );
14035 
14036  return SCIP_OKAY;
14037 }
14038 
14039 /** normalize cumulative condition */
14041  SCIP* scip, /**< SCIP data structure */
14042  int nvars, /**< number of start time variables (activities) */
14043  SCIP_VAR** vars, /**< array of start time variables */
14044  int* durations, /**< array of durations */
14045  int* demands, /**< array of demands */
14046  int* capacity, /**< pointer to store the changed cumulative capacity */
14047  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
14048  int* nchgsides /**< pointer to count number of side changes */
14049  )
14050 {
14051  SCIP_CALL( normalizeCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14052  nchgcoefs, nchgsides) );
14053 
14054  return SCIP_OKAY;
14055 }
14056 
14057 /** searches for a time point within the cumulative condition were the cumulative condition can be split */
14059  SCIP* scip, /**< SCIP data structure */
14060  int nvars, /**< number of variables (jobs) */
14061  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14062  int* durations, /**< array containing corresponding durations */
14063  int* demands, /**< array containing corresponding demands */
14064  int capacity, /**< available cumulative capacity */
14065  int* hmin, /**< pointer to store the left bound of the effective horizon */
14066  int* hmax, /**< pointer to store the right bound of the effective horizon */
14067  int* split /**< point were the cumulative condition can be split */
14068  )
14069 {
14070  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14071  hmin, hmax, split) );
14072 
14073  return SCIP_OKAY;
14074 }
14075 
14076 /** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
14078  SCIP* scip, /**< SCIP data structure */
14079  int nvars, /**< number of start time variables (activities) */
14080  SCIP_VAR** vars, /**< array of start time variables */
14081  int* durations, /**< array of durations */
14082  int hmin, /**< left bound of time axis to be considered */
14083  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14084  SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
14085  SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
14086  SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
14087  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
14088  int* nfixedvars, /**< pointer to store the number of fixed variables */
14089  int* nchgsides, /**< pointer to store the number of changed sides */
14090  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
14091  )
14092 {
14093  if( nvars <= 1 )
14094  return SCIP_OKAY;
14095 
14096  /* presolve constraint form the earlier start time point of view */
14097  SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14098  irrelevants, nfixedvars, nchgsides, cutoff) );
14099 
14100  /* presolve constraint form the latest completion time point of view */
14101  SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14102  irrelevants, nfixedvars, nchgsides, cutoff) );
14103 
14104  return SCIP_OKAY;
14105 }
14106 
14107 /** propagate the given cumulative condition */
14109  SCIP* scip, /**< SCIP data structure */
14110  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
14111  int nvars, /**< number of variables (jobs) */
14112  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14113  int* durations, /**< array containing corresponding durations */
14114  int* demands, /**< array containing corresponding demands */
14115  int capacity, /**< available cumulative capacity */
14116  int hmin, /**< left bound of time axis to be considered (including hmin) */
14117  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14118  SCIP_CONS* cons, /**< constraint which gets propagated */
14119  int* nchgbds, /**< pointer to store the number of variable bound changes */
14120  SCIP_Bool* initialized, /**< was conflict analysis initialized */
14121  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14122  SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14123  )
14124 {
14125  SCIP_CONSHDLR* conshdlr;
14126  SCIP_CONSHDLRDATA* conshdlrdata;
14127  SCIP_Bool redundant;
14128 
14129  assert(scip != NULL);
14130  assert(cons != NULL);
14131  assert(initialized != NULL);
14132  assert(*initialized == FALSE);
14133  assert(cutoff != NULL);
14134  assert(*cutoff == FALSE);
14135 
14136  /* find the cumulative constraint handler */
14137  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14138  if( conshdlr == NULL )
14139  {
14140  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14141  return SCIP_PLUGINNOTFOUND;
14142  }
14143 
14144  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14145  assert(conshdlrdata != NULL);
14146 
14147  redundant = FALSE;
14148 
14149  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14150  nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14151  nchgbds, &redundant, initialized, explanation, cutoff) );
14152 
14153  return SCIP_OKAY;
14154 }
14155 
14156 /** resolve propagation w.r.t. the cumulative condition */
14158  SCIP* scip, /**< SCIP data structure */
14159  int nvars, /**< number of start time variables (activities) */
14160  SCIP_VAR** vars, /**< array of start time variables */
14161  int* durations, /**< array of durations */
14162  int* demands, /**< array of demands */
14163  int capacity, /**< cumulative capacity */
14164  int hmin, /**< left bound of time axis to be considered (including hmin) */
14165  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14166  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14167  int inferinfo, /**< the user information */
14168  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14169  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14170  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14171  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14172  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14173  )
14174 {
14175  SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14176  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14177 
14178  return SCIP_OKAY;
14179 }
14180 
14181 /** this method visualizes the cumulative structure in GML format */
14183  SCIP* scip, /**< SCIP data structure */
14184  SCIP_CONS* cons /**< cumulative constraint */
14185  )
14186 {
14187  SCIP_CONSDATA* consdata;
14188  SCIP_HASHTABLE* vars;
14189  FILE* file;
14190  SCIP_VAR* var;
14191  char filename[SCIP_MAXSTRLEN];
14192  int nvars;
14193  int v;
14194 
14195  SCIP_RETCODE retcode = SCIP_OKAY;
14196 
14197  /* open file */
14198  (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14199  file = fopen(filename, "w");
14200 
14201  /* check if the file was open */
14202  if( file == NULL )
14203  {
14204  SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14205  SCIPprintSysError(filename);
14206  return SCIP_FILECREATEERROR;
14207  }
14208 
14209  consdata = SCIPconsGetData(cons);
14210  assert(consdata != NULL);
14211 
14212  nvars = consdata->nvars;
14213 
14214  SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
14215  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
14216 
14217  /* create opening of the GML format */
14218  SCIPgmlWriteOpening(file, TRUE);
14219 
14220  for( v = 0; v < nvars; ++v )
14221  {
14222  char color[SCIP_MAXSTRLEN];
14223 
14224  var = consdata->vars[v];
14225  assert(var != NULL);
14226 
14227  SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
14228 
14229  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14230  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14231  else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14232  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14233  else
14234  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14235 
14236  SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14237  }
14238 
14239  for( v = 0; v < nvars; ++v )
14240  {
14241  SCIP_VAR** vbdvars;
14242  int nvbdvars;
14243  int b;
14244 
14245  var = consdata->vars[v];
14246  assert(var != NULL);
14247 
14248  vbdvars = SCIPvarGetVlbVars(var);
14249  nvbdvars = SCIPvarGetNVlbs(var);
14250 
14251  for( b = 0; b < nvbdvars; ++b )
14252  {
14253  if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14254  {
14255  SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14256  }
14257  }
14258 
14259 #if 0
14260  vbdvars = SCIPvarGetVubVars(var);
14261  nvbdvars = SCIPvarGetNVubs(var);
14262 
14263  for( b = 0; b < nvbdvars; ++b )
14264  {
14265  if( SCIPhashtableExists(vars, vbdvars[b]) )
14266  {
14267  SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14268  }
14269  }
14270 #endif
14271  }
14272 
14273  /* create closing of the GML format */
14274  SCIPgmlWriteClosing(file);
14275 TERMINATE:
14276  /* close file */
14277  fclose(file);
14278 
14279  SCIPhashtableFree(&vars);
14280 
14281  return retcode;
14282 }
14283 
14284 /** sets method to solve an individual cumulative condition */
14286  SCIP* scip, /**< SCIP data structure */
14287  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14288  )
14289 {
14290  SCIP_CONSHDLR* conshdlr;
14291  SCIP_CONSHDLRDATA* conshdlrdata;
14292 
14293  /* find the cumulative constraint handler */
14294  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14295  if( conshdlr == NULL )
14296  {
14297  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14298  return SCIP_PLUGINNOTFOUND;
14299  }
14300 
14301  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14302  assert(conshdlrdata != NULL);
14303 
14304  conshdlrdata->solveCumulative = solveCumulative;
14305 
14306  return SCIP_OKAY;
14307 }
14308 
14309 /** solves given cumulative condition as independent sub problem
14310  *
14311  * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14312  * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14313  * solver was interrupted.
14314  */
14316  SCIP* scip, /**< SCIP data structure */
14317  int njobs, /**< number of jobs (activities) */
14318  SCIP_Real* ests, /**< array with the earlier start time for each job */
14319  SCIP_Real* lsts, /**< array with the latest start time for each job */
14320  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14321  int* durations, /**< array of durations */
14322  int* demands, /**< array of demands */
14323  int capacity, /**< cumulative capacity */
14324  int hmin, /**< left bound of time axis to be considered (including hmin) */
14325  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14326  SCIP_Real timelimit, /**< time limit for solving in seconds */
14327  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14328  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14329  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14330  SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14331  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14332  SCIP_Bool* error /**< pointer to store if an error occurred */
14333  )
14334 {
14335  SCIP_CONSHDLR* conshdlr;
14336  SCIP_CONSHDLRDATA* conshdlrdata;
14337 
14338  (*solved) = TRUE;
14339  (*infeasible) = FALSE;
14340  (*unbounded) = FALSE;
14341  (*error) = FALSE;
14342 
14343  if( njobs == 0 )
14344  return SCIP_OKAY;
14345 
14346  /* find the cumulative constraint handler */
14347  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14348  if( conshdlr == NULL )
14349  {
14350  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14351  (*error) = TRUE;
14352  return SCIP_PLUGINNOTFOUND;
14353  }
14354 
14355  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14356  assert(conshdlrdata != NULL);
14357 
14358  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14359  if( timelimit > 0.0 && memorylimit > 10 )
14360  {
14361  SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14362  hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14363  }
14364 
14365  return SCIP_OKAY;
14366 }
14367 
14368 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14369  * completion time
14370  */
14372  SCIP* scip, /**< SCIP data structure */
14373  SCIP_PROFILE* profile, /**< resource profile */
14374  int nvars, /**< number of variables (jobs) */
14375  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14376  int* durations, /**< array containing corresponding durations */
14377  int* demands /**< array containing corresponding demands */
14378  )
14379 {
14380  SCIP_VAR* var;
14381  SCIP_HASHMAP* addedvars;
14382  int* copydemands;
14383  int* perm;
14384  int duration;
14385  int impliedest;
14386  int est;
14387  int impliedlct;
14388  int lct;
14389  int v;
14390 
14391  /* create hash map for variables which are added, mapping to their duration */
14392  SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
14393 
14394  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14395  SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14396 
14397  /* sort variables w.r.t. job demands */
14398  for( v = 0; v < nvars; ++v )
14399  {
14400  copydemands[v] = demands[v];
14401  perm[v] = v;
14402  }
14403  SCIPsortDownIntInt(copydemands, perm, nvars);
14404 
14405  /* add each job with its earliest start and latest completion time into the resource profile */
14406  for( v = 0; v < nvars; ++v )
14407  {
14408  int idx;
14409 
14410  idx = perm[v];
14411  assert(idx >= 0 && idx < nvars);
14412 
14413  var = vars[idx];
14414  assert(var != NULL);
14415 
14416  duration = durations[idx];
14417  assert(duration > 0);
14418 
14419  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
14420  SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14421 
14422  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14423  SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14424 
14425  if( impliedest < impliedlct )
14426  {
14427  SCIP_Bool infeasible;
14428  int pos;
14429 
14430  SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14431  assert(!infeasible);
14432  assert(pos == -1);
14433  }
14434 
14435  if( est == impliedest && lct == impliedlct )
14436  {
14437  SCIP_CALL( SCIPhashmapInsert(addedvars, (void*)var, (void*)(size_t)duration) );
14438  }
14439  }
14440 
14441  SCIPfreeBufferArray(scip, &copydemands);
14442  SCIPfreeBufferArray(scip, &perm);
14443 
14444  SCIPhashmapFree(&addedvars);
14445 
14446  return SCIP_OKAY;
14447 }
14448 
14449 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */
14450 int SCIPcomputeHmin(
14451  SCIP* scip, /**< SCIP data structure */
14452  SCIP_PROFILE* profile, /**< worst case resource profile */
14453  int capacity /**< capacity to check */
14454  )
14455 {
14456  int* timepoints;
14457  int* loads;
14458  int ntimepoints;
14459  int t;
14460 
14461  ntimepoints = SCIPprofileGetNTimepoints(profile);
14462  timepoints = SCIPprofileGetTimepoints(profile);
14463  loads = SCIPprofileGetLoads(profile);
14464 
14465  /* find first time point which potentially violates the capacity restriction */
14466  for( t = 0; t < ntimepoints - 1; ++t )
14467  {
14468  /* check if the time point exceed w.r.t. worst case profile the capacity */
14469  if( loads[t] > capacity )
14470  {
14471  assert(t == 0 || loads[t-1] <= capacity);
14472  return timepoints[t];
14473  }
14474  }
14475 
14476  return INT_MAX;
14477 }
14478 
14479 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity is satisfied for sure */
14480 int SCIPcomputeHmax(
14481  SCIP* scip, /**< SCIP data structure */
14482  SCIP_PROFILE* profile, /**< worst case profile */
14483  int capacity /**< capacity to check */
14484  )
14485 {
14486  int* timepoints;
14487  int* loads;
14488  int ntimepoints;
14489  int t;
14490 
14491  ntimepoints = SCIPprofileGetNTimepoints(profile);
14492  timepoints = SCIPprofileGetTimepoints(profile);
14493  loads = SCIPprofileGetLoads(profile);
14494 
14495  /* find last time point which potentially violates the capacity restriction */
14496  for( t = ntimepoints - 1; t >= 0; --t )
14497  {
14498  /* check if at time point t the worst case resource profile exceeds the capacity */
14499  if( loads[t] > capacity )
14500  {
14501  assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14502  return timepoints[t+1];
14503  }
14504  }
14505 
14506  return INT_MIN;
14507 }
14508 
14509 /**@} */
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:8004
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:22604
#define CONSHDLR_SEPAPRIORITY
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4143
int SCIPgetNCheckConss(SCIP *scip)
Definition: scip.c:13004
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:22593
void SCIPbtnodeFree(SCIP_BT *tree, SCIP_BTNODE **node)
Definition: misc.c:8068
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:6291
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip.c:41459
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip.c:46306
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:17490
static SCIP_DECL_CONSCOPY(consCopyCumulative)
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.h:22587
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.c:22523
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30613
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip.c:19649
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47298
SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_setppc.c:9207
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:821
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:8245
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:6314
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:6566
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.c:19509
void * SCIPbtnodeGetData(SCIP_BTNODE *node)
Definition: misc.c:8113
SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
Definition: scip.c:37651
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.c:41226
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:6604
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30636
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17468
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:17276
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:6544
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip.c:4489
static void addEndingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *endtimes, int *endindices, int *freecapacity, int *idx, int nvars)
#define SCIP_MAXSTRLEN
Definition: def.h:259
#define DEFAULT_MAXNODES
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:16863
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.c:6036
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28400
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.c:12663
static SCIP_RETCODE constraintNonOverlappingGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:46813
static long bound
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:30668
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)
Definition: scip.c:47088
#define CONSHDLR_NAME
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17332
#define SCIP_CALL_FINALLY(x, y)
Definition: def.h:392
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)
Definition: scip.c:47015
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.c:8611
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.c:28112
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip.c:18038
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:6363
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:18766
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.c:6205
static void transitiveClosure(SCIP_Bool **adjmatrix, int *ninarcs, int *noutarcs, int nnodes)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:47387
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.c:28213
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:9639
void SCIPbtnodeSetRightchild(SCIP_BTNODE *node, SCIP_BTNODE *right)
Definition: misc.c:8274
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:64
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:278
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.c:4293
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10289
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.c:5894
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:47028
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:10011
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:47100
#define TRUE
Definition: def.h:63
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:27474
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)
Definition: scip.c:27251
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_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:21660
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8265
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17510
#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:16969
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.c:17699
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:8295
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)
Definition: scip.c:27218
#define DEFAULT_LOCALCUTS
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
Definition: scip.c:27155
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22639
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:22602
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:6536
#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.c:5948
#define CONSHDLR_DELAYPROP
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17480
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.c:1235
static TCLIQUE_ISEDGE(tcliqueIsedgeClique)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip.h:22628
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)
Definition: scip.c:46963
SCIP_RETCODE SCIPaddVarVlb(SCIP *scip, SCIP_VAR *var, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconstant, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip.c:23975
#define SCIP_LONGINT_MAX
Definition: def.h:135
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:22632
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip.c:748
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:16873
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:22585
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip.c:1017
#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.c:4804
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8255
SCIP_RETCODE SCIPsetHmaxCumulative(SCIP *scip, SCIP_CONS *cons, int hmax)
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:6337
#define SCIPdebugMsgPrint
Definition: scip.h:456
int SCIPprofileGetLoad(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6375
#define SCIPdebugMsg
Definition: scip.h:455
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip.c:18998
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:6521
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8047
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1343
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.c:27584
SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
Definition: scip.c:9997
#define DEFAULT_NORMALIZE
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
Definition: scip.c:27184
static SCIP_RETCODE deleteTrivilCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, SCIP_Bool *cutoff)
SCIP_Bool SCIPbtnodeIsRoot(SCIP_BTNODE *node)
Definition: misc.c:8173
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)
Definition: scip.c:47435
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
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:16695
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3025
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
Definition: scip.c:27133
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.c:27884
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:17286
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.h:22599
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.c:16115
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:6060
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:8123
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:4113
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12591
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)
Definition: scip.c:46976
void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:13297
void SCIPbtnodeSetLeftchild(SCIP_BTNODE *node, SCIP_BTNODE *left)
Definition: misc.c:8260
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.h:22618
int SCIPgetHmaxCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip.c:19311
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip.h:22633
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition: scip.c:4630
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip.c:928
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:46731
SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:27450
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:10112
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21788
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:7986
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:17542
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:25932
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8205
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:16662
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:6085
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2826
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4133
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)
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_CALL(x)
Definition: def.h:350
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17500
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.c:5061
static TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
Definition: scip.c:27535
SCIP_RETCODE SCIPprofileCreate(SCIP_PROFILE **profile, int capacity)
Definition: misc.c:6271
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17532
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8225
#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.c:27726
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:34661
#define DEFAULT_DETECTDISJUNCTIVE
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip.c:6360
static SCIP_DECL_CONSFREE(consFreeCumulative)
SCIP_Bool SCIPbtnodeIsRightchild(SCIP_BTNODE *node)
Definition: misc.c:8211
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:50
#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:8396
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:8143
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:22620
#define SCIP_UNKNOWN
Definition: def.h:170
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:61
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:9920
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.c:30402
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:43045
#define DEFAULT_USECOVERCUTS
static void freeNodedata(SCIP *scip, SCIP_NODEDATA **nodedata)
SCIP_Bool SCIPprofileFindLeft(SCIP_PROFILE *profile, int timepoint, int *pos)
Definition: misc.c:6389
static SCIP_DECL_EVENTEXEC(eventExecCumulative)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:29091
int SCIPvarGetNLocksUp(SCIP_VAR *var)
Definition: var.c:3217
#define SCIP_DECL_CONSEXITPRE(x)
Definition: type_cons.h:164
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10082
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:8006
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11353
SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
Definition: scip.c:27286
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip.c:4688
void SCIPbtFree(SCIP_BT **tree)
Definition: misc.c:8304
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8115
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:8193
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8185
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8155
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17124
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:41272
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.c:17619
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip.c:37272
#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.c:25575
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:116
int SCIPgetNRuns(SCIP *scip)
Definition: scip.c:42050
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21714
void SCIPprofilePrint(SCIP_PROFILE *profile, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: misc.c:6301
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip.c:6498
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)
Definition: scip.c:47039
#define CONSHDLR_NEEDSCONS
int * SCIPprofileGetTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6343
int SCIPconvertRealToInt(SCIP *scip, SCIP_Real real)
Definition: scip.c:47806
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.c:22819
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:6353
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:35836
SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
Definition: scip.c:4862
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2064
SCIP_Bool SCIPbtIsEmpty(SCIP_BT *tree)
Definition: misc.c:8386
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:11812
#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:8133
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_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)
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:6229
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:30540
void SCIPbtSetRoot(SCIP_BT *tree, SCIP_BTNODE *root)
Definition: misc.c:8409
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.h:22630
static SCIP_RETCODE insertThetanode(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node, SCIP_NODEDATA **nodedatas, int *nnodedatas)
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:8246
static SCIP_RETCODE removeRedundantConss(SCIP *scip, SCIP_CONS **conss, int nconss, int *ndelconss)
static SCIP_RETCODE getActiveVar(SCIP *scip, SCIP_VAR **var, int *scalar, int *constant)
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3162
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5081
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip.c:39882
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47002
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.c:46774
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.c:1920
static SCIP_DECL_CONSPRINT(consPrintCumulative)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:11492
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8016
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.c:22932
static SCIP_RETCODE consdataCollectLinkingCons(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip.c:17350
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.c:27909
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnvelop(SCIP_BTNODE *node)
int SCIPgetNConss(SCIP *scip)
Definition: scip.c:12862
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.c:27761
#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.c:25885
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:6253
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip.c:13790
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30977
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.c:46800
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip.c:11767
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:16781
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.c:25684
int * SCIPgetDemandsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
#define SCIP_Real
Definition: def.h:149
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8235
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.c:1145
static SCIP_DECL_CONSTRANS(consTransCumulative)
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:6567
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:371
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:8175
#define SCIP_INVALID
Definition: def.h:169
#define EVENTHDLR_DESC
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8165
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:31160
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17522
#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:134
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:16959
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.c:31134
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16827
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)
Definition: scip.c:47076
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46989
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:49
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:17342
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.h:22605
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)
Definition: scip.c:47399
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16804
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:9074
void SCIPswapInts(int *value1, int *value2)
Definition: misc.c:9613
SCIP_RETCODE SCIPbtCreate(SCIP_BT **tree, BMS_BLKMEM *blkmem)
Definition: misc.c:8285
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:6333
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:6181
#define SCIPABORT()
Definition: def.h:322
static SCIP_DECL_CONSDELETE(consDeleteCumulative)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:8448
SCIP_RETCODE SCIPvisualizeConsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:38911
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.c:5083
SCIP_Bool SCIPbtnodeIsLeaf(SCIP_BTNODE *node)
Definition: misc.c:8183
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip.c:4746
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.c:4239
SCIP_RETCODE SCIPsetSolveCumulative(SCIP *scip, SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)))
static SCIP_DECL_CONSRESPROP(consRespropCumulative)
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16949
static SCIP_RETCODE varMayRoundDown(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
void SCIPprofileFree(SCIP_PROFILE **profile)
Definition: misc.c:6285
#define CONSHDLR_ENFOPRIORITY
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip.c:780
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:22624
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.c:5994
#define DEFAULT_SEPAOLD
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip.c:27859