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-2019 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scip.zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_cumulative.c
17  * @brief constraint handler for cumulative constraints
18  * @author Timo Berthold
19  * @author Stefan Heinz
20  * @author Jens Schulz
21  *
22  * Given:
23  * - a set of jobs, represented by their integer start time variables \f$S_j\f$, their array of processing times \f$p_j\f$ and of
24  * their demands \f$d_j\f$.
25  * - an integer resource capacity \f$C\f$
26  *
27  * The cumulative constraint ensures that for each point in time \f$t\f$ \f$\sum_{j: S_j \leq t < S_j + p_j} d_j \leq C\f$ holds.
28  *
29  * Separation:
30  * - can be done using binary start time model, see Pritskers, Watters and Wolfe
31  * - or by just separating relatively weak cuts on the integer start time variables
32  *
33  * Propagation:
34  * - time tabling, Klein & Scholl (1999)
35  * - Edge-finding from Petr Vilim, adjusted and simplified for dynamic repropagation
36  * (2009)
37  * - energetic reasoning, see Baptiste, Le Pape, Nuijten (2001)
38  *
39  */
40 
41 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
42 
43 #include <assert.h>
44 #include <string.h>
45 
46 #include "tclique/tclique.h"
47 #include "scip/cons_cumulative.h"
48 #include "scip/cons_linking.h"
49 #include "scip/cons_knapsack.h"
50 #include "scip/scipdefplugins.h"
51 
52 /**@name Constraint handler properties
53  *
54  * @{
55  */
56 
57 /* constraint handler properties */
58 #define CONSHDLR_NAME "cumulative"
59 #define CONSHDLR_DESC "cumulative constraint handler"
60 #define CONSHDLR_SEPAPRIORITY 2100000 /**< priority of the constraint handler for separation */
61 #define CONSHDLR_ENFOPRIORITY -2040000 /**< priority of the constraint handler for constraint enforcing */
62 #define CONSHDLR_CHECKPRIORITY -3030000 /**< priority of the constraint handler for checking feasibility */
63 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
64 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
65 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
66  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
67 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
68 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
69 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
70 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
71 
72 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
73 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
74 
75 /**@} */
76 
77 /**@name Default parameter values
78  *
79  * @{
80  */
81 
82 /* default parameter values */
83 
84 /* separation */
85 #define DEFAULT_USEBINVARS FALSE /**< should the binary representation be used? */
86 #define DEFAULT_LOCALCUTS FALSE /**< should cuts be added only locally? */
87 #define DEFAULT_USECOVERCUTS TRUE /**< should covering cuts be added? */
88 #define DEFAULT_CUTSASCONSS TRUE /**< should the cuts be created as knapsack constraints? */
89 #define DEFAULT_SEPAOLD TRUE /**< shall old sepa algo be applied? */
90 
91 /* propagation */
92 #define DEFAULT_TTINFER TRUE /**< should time-table (core-times) propagator be used to infer bounds? */
93 #define DEFAULT_EFCHECK FALSE /**< should edge-finding be used to detect an overload? */
94 #define DEFAULT_EFINFER FALSE /**< should edge-finding be used to infer bounds? */
95 #define DEFAULT_USEADJUSTEDJOBS FALSE /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
96 #define DEFAULT_TTEFCHECK TRUE /**< should time-table edge-finding be used to detect an overload? */
97 #define DEFAULT_TTEFINFER TRUE /**< should time-table edge-finding be used to infer bounds? */
98 
99 /* presolving */
100 #define DEFAULT_DUALPRESOLVE TRUE /**< should dual presolving be applied? */
101 #define DEFAULT_COEFTIGHTENING FALSE /**< should coeffisient tightening be applied? */
102 #define DEFAULT_NORMALIZE TRUE /**< should demands and capacity be normalized? */
103 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
104 #define DEFAULT_DISJUNCTIVE TRUE /**< extract disjunctive constraints? */
105 #define DEFAULT_DETECTDISJUNCTIVE TRUE /**< search for conflict set via maximal cliques to detect disjunctive constraints */
106 #define DEFAULT_DETECTVARBOUNDS TRUE /**< search for conflict set via maximal cliques to detect variable bound constraints */
107 #define DEFAULT_MAXNODES 10000LL /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
109 /* enforcement */
110 #define DEFAULT_FILLBRANCHCANDS FALSE /**< should branching candidates be added to storage? */
112 /* conflict analysis */
113 #define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used during conflict analysis? */
115 /**@} */
116 
117 /**@name Event handler properties
118  *
119  * @{
120  */
121 
122 #define EVENTHDLR_NAME "cumulative"
123 #define EVENTHDLR_DESC "bound change event handler for cumulative constraints"
125 /**@} */
126 
127 /*
128  * Data structures
129  */
130 
131 /** constraint data for cumulative constraints */
132 struct SCIP_ConsData
133 {
134  SCIP_VAR** vars; /**< array of variable representing the start time of each job */
135  SCIP_Bool* downlocks; /**< array to store if the variable has a down lock */
136  SCIP_Bool* uplocks; /**< array to store if the variable has an uplock */
137  SCIP_CONS** linkingconss; /**< array of linking constraints for the integer variables */
138  SCIP_ROW** demandrows; /**< array of rows of linear relaxation of this problem */
139  SCIP_ROW** scoverrows; /**< array of rows of small cover cuts of this problem */
140  SCIP_ROW** bcoverrows; /**< array of rows of big cover cuts of this problem */
141  int* demands; /**< array containing corresponding demands */
142  int* durations; /**< array containing corresponding durations */
143  SCIP_Real resstrength1; /**< stores the resource strength 1*/
144  SCIP_Real resstrength2; /**< stores the resource strength 2 */
145  SCIP_Real cumfactor1; /**< stroes the cumulativeness of the constraint */
146  SCIP_Real disjfactor1; /**< stores the disjunctiveness of the constraint */
147  SCIP_Real disjfactor2; /**< stores the disjunctiveness of the constraint */
148  SCIP_Real estimatedstrength;
149  int nvars; /**< number of variables */
150  int varssize; /**< size of the arrays */
151  int ndemandrows; /**< number of rows of cumulative constrint for linear relaxation */
152  int demandrowssize; /**< size of array rows of demand rows */
153  int nscoverrows; /**< number of rows of small cover cuts */
154  int scoverrowssize; /**< size of array of small cover cuts */
155  int nbcoverrows; /**< number of rows of big cover cuts */
156  int bcoverrowssize; /**< size of array of big cover cuts */
157  int capacity; /**< available cumulative capacity */
158 
159  int hmin; /**< left bound of time axis to be considered (including hmin) */
160  int hmax; /**< right bound of time axis to be considered (not including hmax) */
161 
162  unsigned int signature; /**< constraint signature which is need for pairwise comparison */
163 
164  unsigned int validsignature:1; /**< is the signature valid */
165  unsigned int normalized:1; /**< is the constraint normalized */
166  unsigned int covercuts:1; /**< cover cuts are created? */
167  unsigned int propagated:1; /**< is constraint propagted */
168  unsigned int varbounds:1; /**< bool to store if variable bound strengthening was already preformed */
169  unsigned int triedsolving:1; /**< bool to store if we tried already to solve that constraint as independent subproblem */
170 
171 #ifdef SCIP_STATISTIC
172  int maxpeak;
173 #endif
174 };
175 
176 /** constraint handler data */
177 struct SCIP_ConshdlrData
178 {
179  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
180 
181  SCIP_Bool usebinvars; /**< should the binary variables be used? */
182  SCIP_Bool cutsasconss; /**< should the cumulative constraint create cuts as knapsack constraints? */
183  SCIP_Bool ttinfer; /**< should time-table (core-times) propagator be used to infer bounds? */
184  SCIP_Bool efcheck; /**< should edge-finding be used to detect an overload? */
185  SCIP_Bool efinfer; /**< should edge-finding be used to infer bounds? */
186  SCIP_Bool useadjustedjobs; /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
187  SCIP_Bool ttefcheck; /**< should time-table edge-finding be used to detect an overload? */
188  SCIP_Bool ttefinfer; /**< should time-table edge-finding be used to infer bounds? */
189  SCIP_Bool localcuts; /**< should cuts be added only locally? */
190  SCIP_Bool usecovercuts; /**< should covering cuts be added? */
191  SCIP_Bool sepaold; /**< shall old sepa algo be applied? */
192 
193  SCIP_Bool fillbranchcands; /**< should branching candidates be added to storage? */
194 
195  SCIP_Bool dualpresolve; /**< should dual presolving be applied? */
196  SCIP_Bool coeftightening; /**< should coeffisient tightening be applied? */
197  SCIP_Bool normalize; /**< should demands and capacity be normalized? */
198  SCIP_Bool disjunctive; /**< extract disjunctive constraints? */
199  SCIP_Bool detectdisjunctive; /**< search for conflict set via maximal cliques to detect disjunctive constraints */
200  SCIP_Bool detectvarbounds; /**< search for conflict set via maximal cliques to detect variable bound constraints */
201  SCIP_Bool usebdwidening; /**< should bound widening be used during conflict analysis? */
202  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
203  SCIP_Bool detectedredundant; /**< was detection of redundant constraints already performed? */
204 
205  SCIP_Longint maxnodes; /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
206 
207  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)); /**< method to use a single cumulative condition */
208 
209  /* statistic values which are collected if SCIP_STATISTIC is defined */
210 #ifdef SCIP_STATISTIC
211  SCIP_Longint nlbtimetable; /**< number of times the lower bound was tightened by the time-table propagator */
212  SCIP_Longint nubtimetable; /**< number of times the upper bound was tightened by the time-table propagator */
213  SCIP_Longint ncutofftimetable; /**< number of times the a cutoff was detected due to time-table propagator */
214  SCIP_Longint nlbedgefinder; /**< number of times the lower bound was tightened by the edge-finder propagator */
215  SCIP_Longint nubedgefinder; /**< number of times the upper bound was tightened by the edge-finder propagator */
216  SCIP_Longint ncutoffedgefinder; /**< number of times the a cutoff was detected due to edge-finder propagator */
217  SCIP_Longint ncutoffoverload; /**< number of times the a cutoff was detected due to overload checking via edge-finding */
218  SCIP_Longint nlbTTEF; /**< number of times the lower bound was tightened by time-table edge-finding */
219  SCIP_Longint nubTTEF; /**< number of times the upper bound was tightened by time-table edge-finding */
220  SCIP_Longint ncutoffoverloadTTEF;/**< number of times the a cutoff was detected due to overload checking via time-table edge-finding */
221 
222  int nirrelevantjobs; /**< number of time a irrelevant/redundant jobs was removed form a constraint */
223  int nalwaysruns; /**< number of time a job removed form a constraint which run completely during the effective horizon */
224  int nremovedlocks; /**< number of times a up or down lock was removed */
225  int ndualfixs; /**< number of times a dual fix was performed by a single constraint */
226  int ndecomps; /**< number of times a constraint was decomposed */
227  int ndualbranchs; /**< number of times a dual branch was discoverd and applicable via probing */
228  int nallconsdualfixs; /**< number of times a dual fix was performed due to knowledge of all cumulative constraints */
229  int naddedvarbounds; /**< number of added variable bounds constraints */
230  int naddeddisjunctives; /**< number of added disjunctive constraints */
231 
232  SCIP_Bool iscopy; /**< Boolean to store if constraint handler is part of a copy */
233 #endif
234 };
235 
236 /**@name Inference Information Methods
237  *
238  * An inference information can be passed with each domain reduction to SCIP. This information is passed back to the
239  * constraint handler if the corresponding bound change has to be explained. It can be used to store information which
240  * help to construct a reason/explanation for a bound change. The inference information is limited to size of integer.
241  *
242  * In case of the cumulative constraint handler we store the used propagation algorithms for that particular bound
243  * change and the earliest start and latest completion time of all jobs in the conflict set.
244  *
245  * @{
246  */
247 
248 /** Propagation rules */
249 enum Proprule
250 {
251  PROPRULE_1_CORETIMES = 1, /**< core-time propagator */
252  PROPRULE_2_EDGEFINDING = 2, /**< edge-finder */
253  PROPRULE_3_TTEF = 3 /**< time-table edeg-finding */
254 };
255 typedef enum Proprule PROPRULE;
257 /** inference information */
258 struct InferInfo
259 {
260  union
261  {
262  /** struct to use the inference information */
263  struct
264  {
265  unsigned int proprule:2; /**< propagation rule that was applied */
266  unsigned int data1:15; /**< data field one */
267  unsigned int data2:15; /**< data field two */
268  } asbits;
269  int asint; /**< inference information as a single int value */
270  } val;
271 };
272 typedef struct InferInfo INFERINFO;
274 /** converts an integer into an inference information */
275 static
276 INFERINFO intToInferInfo(
277  int i /**< integer to convert */
278  )
279 {
280  INFERINFO inferinfo;
281 
282  inferinfo.val.asint = i;
283 
284  return inferinfo;
285 }
286 
287 /** converts an inference information into an int */
288 static
289 int inferInfoToInt(
290  INFERINFO inferinfo /**< inference information to convert */
291  )
292 {
293  return inferinfo.val.asint;
294 }
295 
296 /** returns the propagation rule stored in the inference information */
297 static
299  INFERINFO inferinfo /**< inference information to convert */
300  )
301 {
302  return (PROPRULE) inferinfo.val.asbits.proprule;
303 }
304 
305 /** returns data field one of the inference information */
306 static
308  INFERINFO inferinfo /**< inference information to convert */
309  )
310 {
311  return (int) inferinfo.val.asbits.data1;
312 }
313 
314 /** returns data field two of the inference information */
315 static
317  INFERINFO inferinfo /**< inference information to convert */
318  )
319 {
320  return (int) inferinfo.val.asbits.data2;
321 }
322 
323 
324 /** constructs an inference information out of a propagation rule, an earliest start and a latest completion time */
325 static
326 INFERINFO getInferInfo(
327  PROPRULE proprule, /**< propagation rule that deduced the value */
328  int data1, /**< data field one */
329  int data2 /**< data field two */
330  )
331 {
332  INFERINFO inferinfo;
333 
334  /* check that the data menber are in the range of the available bits */
335  assert((int)proprule <= (1<<2)-1); /*lint !e685*/
336  assert(data1 >= 0 && data1 < (1<<15));
337  assert(data2 >= 0 && data2 < (1<<15));
338 
339  inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
340  inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
341  inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
342 
343  return inferinfo;
344 }
345 
346 /**@} */
347 
348 /*
349  * Local methods
350  */
351 
352 /**@name Miscellaneous Methods
353  *
354  * @{
355  */
356 
357 #ifndef NDEBUG
358 
359 /** compute the core of a job which lies in certain interval [begin, end) */
360 static
362  int begin, /**< begin of the interval */
363  int end, /**< end of the interval */
364  int ect, /**< earliest completion time */
365  int lst /**< latest start time */
366  )
367 {
368  int core;
369 
370  core = MAX(0, MIN(end, ect) - MAX(lst, begin));
371 
372  return core;
373 }
374 #else
375 #define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
376 #endif
377 
378 /** returns the implied earliest start time */
379 static
381  SCIP* scip, /**< SCIP data structure */
382  SCIP_VAR* var, /**< variable for which the implied est should be returned */
383  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
384  int* est /**< pointer to store the implied earliest start time */
385  )
386 { /*lint --e{715}*/
387 #if 0
388  SCIP_VAR** vbdvars;
389  SCIP_VAR* vbdvar;
390  SCIP_Real* vbdcoefs;
391  SCIP_Real* vbdconsts;
392  void* image;
393  int nvbdvars;
394  int v;
395 #endif
396 
397  (*est) = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
398 
399 #if 0
400  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
401 
402  nvbdvars = SCIPvarGetNVlbs(var);
403  vbdvars = SCIPvarGetVlbVars(var);
404  vbdcoefs = SCIPvarGetVlbCoefs(var);
405  vbdconsts = SCIPvarGetVlbConstants(var);
406 
407  for( v = 0; v < nvbdvars; ++v )
408  {
409  vbdvar = vbdvars[v];
410  assert(vbdvar != NULL);
411 
412  image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
413 
414  if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
415  {
416  int duration;
417  int vbdconst;
418 
419  duration = (int)(size_t)image;
420  vbdconst = SCIPconvertRealToInt(scip, vbdconsts[v]);
421 
422  SCIPdebugMsg(scip, "check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
424  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
425 
426  if( duration >= vbdconst )
427  {
428  int impliedest;
429 
430  impliedest = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
431 
432  if( (*est) < impliedest )
433  {
434  (*est) = impliedest;
435 
436  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
437  }
438  }
439  }
440  }
441 #endif
442 
443  return SCIP_OKAY;
444 }
445 
446 /** returns the implied latest completion time */
447 static
449  SCIP* scip, /**< SCIP data structure */
450  SCIP_VAR* var, /**< variable for which the implied est should be returned */
451  int duration, /**< duration of the given job */
452  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
453  int* lct /**< pointer to store the implied latest completion time */
454  )
455 { /*lint --e{715}*/
456 #if 0
457  SCIP_VAR** vbdvars;
458  SCIP_VAR* vbdvar;
459  SCIP_Real* vbdcoefs;
460  SCIP_Real* vbdconsts;
461  int nvbdvars;
462  int v;
463 #endif
464 
465  (*lct) = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
466 
467 #if 0
468  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
469 
470  nvbdvars = SCIPvarGetNVubs(var);
471  vbdvars = SCIPvarGetVubVars(var);
472  vbdcoefs = SCIPvarGetVubCoefs(var);
473  vbdconsts = SCIPvarGetVubConstants(var);
474 
475  for( v = 0; v < nvbdvars; ++v )
476  {
477  vbdvar = vbdvars[v];
478  assert(vbdvar != NULL);
479 
480  if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
481  {
482  int vbdconst;
483 
484  vbdconst = SCIPconvertRealToInt(scip, -vbdconsts[v]);
485 
486  SCIPdebugMsg(scip, "check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
488  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
489 
490  if( duration >= -vbdconst )
491  {
492  int impliedlct;
493 
494  impliedlct = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
495 
496  if( (*lct) > impliedlct )
497  {
498  (*lct) = impliedlct;
499 
500  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
501  }
502  }
503  }
504  }
505 #endif
506 
507  return SCIP_OKAY;
508 }
509 
510 /** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
511 static
513  SCIP* scip, /**< SCIP data structure */
514  SCIP_CONSDATA* consdata, /**< constraint data */
515  SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
516  int** coefs, /**< pointer to store the coefficients */
517  int* nvars, /**< number if collect binary variables */
518  int* startindices, /**< permutation with rspect to the start times */
519  int curtime, /**< current point in time */
520  int nstarted, /**< number of jobs that start before the curtime or at curtime */
521  int nfinished /**< number of jobs that finished before curtime or at curtime */
522  )
523 {
524  int nrowvars;
525  int startindex;
526  int size;
527 
528  size = 10;
529  nrowvars = 0;
530  startindex = nstarted - 1;
531 
532  SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
533  SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
534 
535  /* search for the (nstarted - nfinished) jobs which are active at curtime */
536  while( nstarted - nfinished > nrowvars )
537  {
538  SCIP_VAR* var;
539  int endtime;
540  int duration;
541  int demand;
542  int varidx;
543 
544  /* collect job information */
545  varidx = startindices[startindex];
546  assert(varidx >= 0 && varidx < consdata->nvars);
547 
548  var = consdata->vars[varidx];
549  duration = consdata->durations[varidx];
550  demand = consdata->demands[varidx];
551  assert(var != NULL);
552 
553  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
554 
555  /* check the end time of this job is larger than the curtime; in this case the job is still running */
556  if( endtime > curtime )
557  {
558  SCIP_VAR** binvars;
559  int* vals;
560  int nbinvars;
561  int start;
562  int end;
563  int b;
564 
565  /* check if the linking constraints exists */
566  assert(SCIPexistsConsLinking(scip, var));
567  assert(SCIPgetConsLinking(scip, var) != NULL);
568  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
569 
570  /* collect linking constraint information */
571  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
572  vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
573 
574  start = curtime - duration + 1;
575  end = MIN(curtime, endtime - duration);
576 
577  for( b = 0; b < nbinvars; ++b )
578  {
579  if( vals[b] < start )
580  continue;
581 
582  if( vals[b] > end )
583  break;
584 
585  assert(binvars[b] != NULL);
586 
587  /* ensure array proper array size */
588  if( size == *nvars )
589  {
590  size *= 2;
591  SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
592  SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
593  }
594 
595  (*vars)[*nvars] = binvars[b];
596  (*coefs)[*nvars] = demand;
597  (*nvars)++;
598  }
599  nrowvars++;
600  }
601 
602  startindex--;
603  }
604 
605  return SCIP_OKAY;
606 }
607 
608 /** collect all integer variable which belong to jobs which can run at the point of interest */
609 static
611  SCIP* scip, /**< SCIP data structure */
612  SCIP_CONSDATA* consdata, /**< constraint data */
613  SCIP_VAR*** activevars, /**< jobs that are currently running */
614  int* startindices, /**< permutation with rspect to the start times */
615  int curtime, /**< current point in time */
616  int nstarted, /**< number of jobs that start before the curtime or at curtime */
617  int nfinished, /**< number of jobs that finished before curtime or at curtime */
618  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
619  int* lhs /**< lhs for the new row sum of lbs + minoffset */
620  )
621 {
622  SCIP_VAR* var;
623  int startindex;
624  int endtime;
625  int duration;
626  int starttime;
627 
628  int varidx;
629  int sumofstarts;
630  int mindelta;
631  int counter;
632 
633  assert(curtime >= consdata->hmin);
634  assert(curtime < consdata->hmax);
635 
636  counter = 0;
637  sumofstarts = 0;
638 
639  mindelta = INT_MAX;
640 
641  startindex = nstarted - 1;
642 
643  /* search for the (nstarted - nfinished) jobs which are active at curtime */
644  while( nstarted - nfinished > counter )
645  {
646  assert(startindex >= 0);
647 
648  /* collect job information */
649  varidx = startindices[startindex];
650  assert(varidx >= 0 && varidx < consdata->nvars);
651 
652  var = consdata->vars[varidx];
653  duration = consdata->durations[varidx];
654  assert(duration > 0);
655  assert(var != NULL);
656 
657  if( lower )
658  starttime = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
659  else
660  starttime = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
661 
662  endtime = MIN(starttime + duration, consdata->hmax);
663 
664  /* check the end time of this job is larger than the curtime; in this case the job is still running */
665  if( endtime > curtime )
666  {
667  (*activevars)[counter] = var;
668  sumofstarts += starttime;
669  mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
670  counter++;
671  }
672 
673  startindex--;
674  }
675 
676  assert(mindelta > 0);
677  *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
678 
679  return SCIP_OKAY;
680 }
681 
682 /** initialize the sorted event point arrays */
683 static
685  SCIP* scip, /**< SCIP data structure */
686  int nvars, /**< number of start time variables (activities) */
687  SCIP_VAR** vars, /**< array of start time variables */
688  int* durations, /**< array of durations per start time variable */
689  int* starttimes, /**< array to store sorted start events */
690  int* endtimes, /**< array to store sorted end events */
691  int* startindices, /**< permutation with rspect to the start times */
692  int* endindices, /**< permutation with rspect to the end times */
693  SCIP_Bool local /**< shall local bounds be used */
694  )
695 {
696  SCIP_VAR* var;
697  int j;
698 
699  assert(vars != NULL || nvars == 0);
700 
701  /* assign variables, start and endpoints to arrays */
702  for ( j = 0; j < nvars; ++j )
703  {
704  assert(vars != NULL);
705 
706  var = vars[j];
707  assert(var != NULL);
708 
709  if( local )
710  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
711  else
712  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
713 
714  startindices[j] = j;
715 
716  if( local )
717  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
718  else
719  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
720 
721  endindices[j] = j;
722  }
723 
724  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
725  SCIPsortIntInt(starttimes, startindices, j);
726  SCIPsortIntInt(endtimes, endindices, j);
727 }
728 
729 /** initialize the sorted event point arrays w.r.t. the given primal solutions */
730 static
732  SCIP* scip, /**< SCIP data structure */
733  SCIP_SOL* sol, /**< solution */
734  int nvars, /**< number of start time variables (activities) */
735  SCIP_VAR** vars, /**< array of start time variables */
736  int* durations, /**< array of durations per start time variable */
737  int* starttimes, /**< array to store sorted start events */
738  int* endtimes, /**< array to store sorted end events */
739  int* startindices, /**< permutation with rspect to the start times */
740  int* endindices /**< permutation with rspect to the end times */
741  )
742 {
743  SCIP_VAR* var;
744  int j;
745 
746  assert(vars != NULL || nvars == 0);
747 
748  /* assign variables, start and endpoints to arrays */
749  for ( j = 0; j < nvars; ++j )
750  {
751  assert(vars != NULL);
752 
753  var = vars[j];
754  assert(var != NULL);
755 
756  starttimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
757  startindices[j] = j;
758 
759  endtimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
760  endindices[j] = j;
761  }
762 
763  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
764  SCIPsortIntInt(starttimes, startindices, j);
765  SCIPsortIntInt(endtimes, endindices, j);
766 }
767 
768 /** initialize the sorted event point arrays
769  *
770  * @todo Check the separation process!
771  */
772 static
774  SCIP* scip, /**< SCIP data structure */
775  SCIP_CONSDATA* consdata, /**< constraint data */
776  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
777  int* starttimes, /**< array to store sorted start events */
778  int* endtimes, /**< array to store sorted end events */
779  int* startindices, /**< permutation with rspect to the start times */
780  int* endindices, /**< permutation with rspect to the end times */
781  int* nvars, /**< number of variables that are integral */
782  SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
783  )
784 {
785  SCIP_VAR* var;
786  int tmpnvars;
787  int j;
788 
789  tmpnvars = consdata->nvars;
790  *nvars = 0;
791 
792  /* assign variables, start and endpoints to arrays */
793  for ( j = 0; j < tmpnvars; ++j )
794  {
795  var = consdata->vars[j];
796  assert(var != NULL);
797  assert(consdata->durations[j] > 0);
798  assert(consdata->demands[j] > 0);
799 
800  if( lower )
801  {
802  /* only consider jobs that are at their lower or upper bound */
803  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
804  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
805  continue;
806 
807  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
808  startindices[*nvars] = j;
809 
810  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
811  endindices[*nvars] = j;
812 
813  SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
814  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
815  consdata->durations[j],
816  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
817  consdata->demands[startindices[*nvars]]);
818 
819  (*nvars)++;
820  }
821  else
822  {
823  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
824  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
825  continue;
826 
827  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
828  startindices[*nvars] = j;
829 
830  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
831  endindices[*nvars] = j;
832 
833  SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
834  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
835  consdata->durations[j],
836  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
837  consdata->demands[startindices[*nvars]]);
838 
839  (*nvars)++;
840  }
841  }
842 
843  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
844  SCIPsortIntInt(starttimes, startindices, *nvars);
845  SCIPsortIntInt(endtimes, endindices, *nvars);
846 
847 #ifdef SCIP_DEBUG
848  SCIPdebugMsg(scip, "sorted output %d\n", *nvars);
849 
850  for ( j = 0; j < *nvars; ++j )
851  {
852  SCIPdebugMsg(scip, "%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
853  startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
854  consdata->demands[startindices[j]]);
855  }
856 
857  for ( j = 0; j < *nvars; ++j )
858  {
859  SCIPdebugMsg(scip, "%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
860  consdata->demands[endindices[j]]);
861  }
862 #endif
863 }
864 
865 #ifdef SCIP_STATISTIC
866 /** this method checks for relevant intervals for energetic reasoning */
867 static
868 SCIP_RETCODE computeRelevantEnergyIntervals(
869  SCIP* scip, /**< SCIP data structure */
870  int nvars, /**< number of start time variables (activities) */
871  SCIP_VAR** vars, /**< array of start time variables */
872  int* durations, /**< array of durations */
873  int* demands, /**< array of demands */
874  int capacity, /**< cumulative capacity */
875  int hmin, /**< left bound of time axis to be considered (including hmin) */
876  int hmax, /**< right bound of time axis to be considered (not including hmax) */
877  int** timepoints, /**< array to store relevant points in time */
878  SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
879  int* ntimepoints, /**< pointer to store the number of timepoints */
880  int* maxdemand, /**< pointer to store maximum over all demands */
881  SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
882  )
883 {
884  int* starttimes; /* stores when each job is starting */
885  int* endtimes; /* stores when each job ends */
886  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
887  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
888 
889  SCIP_Real totaldemand;
890  int curtime; /* point in time which we are just checking */
891  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
892 
893  int j;
894 
895  assert( scip != NULL );
896  assert(durations != NULL);
897  assert(demands != NULL);
898  assert(capacity >= 0);
899 
900  /* if no activities are associated with this cumulative then this constraint is redundant */
901  if( nvars == 0 )
902  return SCIP_OKAY;
903 
904  assert(vars != NULL);
905 
906  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
907  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
908  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
909  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
910 
911  /* create event point arrays */
912  createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
913 
914  endindex = 0;
915  totaldemand = 0.0;
916 
917  *ntimepoints = 0;
918  (*timepoints)[0] = starttimes[0];
919  (*cumulativedemands)[0] = 0;
920  *maxdemand = 0;
921 
922  /* check each startpoint of a job whether the capacity is kept or not */
923  for( j = 0; j < nvars; ++j )
924  {
925  int lct;
926  int idx;
927 
928  curtime = starttimes[j];
929 
930  if( curtime >= hmax )
931  break;
932 
933  /* free all capacity usages of jobs the are no longer running */
934  while( endindex < nvars && endtimes[endindex] <= curtime )
935  {
936  int est;
937 
938  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
939  {
940  (*ntimepoints)++;
941  (*timepoints)[*ntimepoints] = endtimes[endindex];
942  (*cumulativedemands)[*ntimepoints] = 0;
943  }
944 
945  idx = endindices[endindex];
946  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
947  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
948  endindex++;
949 
950  (*cumulativedemands)[*ntimepoints] = totaldemand;
951  }
952 
953  idx = startindices[j];
954  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
955  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
956 
957  if( (*timepoints)[*ntimepoints] < curtime )
958  {
959  (*ntimepoints)++;
960  (*timepoints)[*ntimepoints] = curtime;
961  (*cumulativedemands)[*ntimepoints] = 0;
962  }
963 
964  (*cumulativedemands)[*ntimepoints] = totaldemand;
965 
966  /* add the relative capacity requirements for all job which start at the curtime */
967  while( j+1 < nvars && starttimes[j+1] == curtime )
968  {
969  ++j;
970  idx = startindices[j];
971  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
972  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
973 
974  (*cumulativedemands)[*ntimepoints] = totaldemand;
975  }
976  } /*lint --e{850}*/
977 
978  /* free all capacity usages of jobs that are no longer running */
979  while( endindex < nvars/* && endtimes[endindex] < hmax*/)
980  {
981  int est;
982  int idx;
983 
984  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
985  {
986  (*ntimepoints)++;
987  (*timepoints)[*ntimepoints] = endtimes[endindex];
988  (*cumulativedemands)[*ntimepoints] = 0;
989  }
990 
991  idx = endindices[endindex];
992  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
993  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
994  (*cumulativedemands)[*ntimepoints] = totaldemand;
995 
996  ++endindex;
997  }
998 
999  (*ntimepoints)++;
1000  /* compute minimum free capacity */
1001  (*minfreecapacity) = INT_MAX;
1002  for( j = 0; j < *ntimepoints; ++j )
1003  {
1004  if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
1005  *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
1006  }
1007 
1008  /* free buffer arrays */
1009  SCIPfreeBufferArray(scip, &endindices);
1010  SCIPfreeBufferArray(scip, &startindices);
1011  SCIPfreeBufferArray(scip, &endtimes);
1012  SCIPfreeBufferArray(scip, &starttimes);
1013 
1014  return SCIP_OKAY;
1015 }
1016 
1017 /** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1018 static
1019 SCIP_RETCODE evaluateCumulativeness(
1020  SCIP* scip, /**< pointer to scip */
1021  SCIP_CONS* cons /**< cumulative constraint */
1022  )
1023 {
1024  SCIP_CONSDATA* consdata;
1025  int nvars;
1026  int v;
1027  int capacity;
1028 
1029  /* output values: */
1030  SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
1031  SCIP_Real cumfactor1;
1032  SCIP_Real resstrength1; /* overall strength */
1033  SCIP_Real resstrength2; /* timepoint wise maximum */
1034 
1035  /* helpful variables: */
1036  SCIP_Real globalpeak;
1037  SCIP_Real globalmaxdemand;
1038 
1039  /* get constraint data structure */
1040  consdata = SCIPconsGetData(cons);
1041  assert(consdata != NULL);
1042 
1043  nvars = consdata->nvars;
1044  capacity = consdata->capacity;
1045  globalpeak = 0.0;
1046  globalmaxdemand = 0.0;
1047 
1048  disjfactor2 = 0.0;
1049  cumfactor1 = 0.0;
1050  resstrength2 = 0.0;
1051 
1052  /* check each starting time (==each job, but inefficient) */
1053  for( v = 0; v < nvars; ++v )
1054  {
1055  SCIP_Real peak;
1056  SCIP_Real maxdemand;
1057  SCIP_Real deltademand;
1058  int ndemands;
1059  int nlarge;
1060 
1061  int timepoint;
1062  int j;
1063  timepoint = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
1064  peak = consdata->demands[v];
1065  ndemands = 1;
1066  maxdemand = 0;
1067  nlarge = 0;
1068 
1069  if( consdata->demands[v] > capacity / 3 )
1070  nlarge++;
1071 
1072  for( j = 0; j < nvars; ++j )
1073  {
1074  int lb;
1075 
1076  if( j == v )
1077  continue;
1078 
1079  maxdemand = 0.0;
1080  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
1081 
1082  if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
1083  {
1084  peak += consdata->demands[j];
1085  ndemands++;
1086 
1087  if( consdata->demands[j] > consdata->capacity / 3 )
1088  nlarge++;
1089  }
1090  }
1091 
1092  deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
1093  globalpeak = MAX(globalpeak, peak);
1094  globalmaxdemand = MAX(globalmaxdemand, maxdemand);
1095 
1096  if( peak > capacity )
1097  {
1098  disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
1099  cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
1100  resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
1101  }
1102  }
1103 
1104  resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
1105 
1106  consdata->maxpeak = SCIPconvertRealToInt(scip, globalpeak);
1107  consdata->disjfactor2 = disjfactor2;
1108  consdata->cumfactor1 = cumfactor1;
1109  consdata->resstrength2 = resstrength2;
1110  consdata->resstrength1 = resstrength1;
1111 
1112  /* get estimated res strength */
1113  {
1114  int* timepoints;
1115  SCIP_Real* estimateddemands;
1116  int ntimepoints;
1117  int maxdemand;
1118  SCIP_Real minfreecapacity;
1119 
1120  SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
1121  SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
1122 
1123  ntimepoints = 0;
1124  minfreecapacity = INT_MAX;
1125 
1126  SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
1127  consdata->durations, consdata->demands,
1128  capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1129  &ntimepoints, &maxdemand, &minfreecapacity) );
1130 
1131  /* free buffer arrays */
1132  SCIPfreeBufferArray(scip, &estimateddemands);
1133  SCIPfreeBufferArray(scip, &timepoints);
1134 
1135  consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
1136  }
1137 
1138  SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
1139  SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
1140  consdata->estimatedstrength);
1141 
1142  return SCIP_OKAY;
1143 }
1144 #endif
1145 
1146 /** gets the active variables together with the constant */
1147 static
1149  SCIP* scip, /**< SCIP data structure */
1150  SCIP_VAR** var, /**< pointer to store the active variable */
1151  int* scalar, /**< pointer to store the scalar */
1152  int* constant /**< pointer to store the constant */
1153  )
1154 {
1155  if( !SCIPvarIsActive(*var) )
1156  {
1157  SCIP_Real realscalar;
1158  SCIP_Real realconstant;
1159 
1160  realscalar = 1.0;
1161  realconstant = 0.0;
1162 
1164 
1165  /* transform variable to active variable */
1166  SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
1167  assert(!SCIPisZero(scip, realscalar));
1168  assert(SCIPvarIsActive(*var));
1169 
1170  if( realconstant < 0.0 )
1171  (*constant) = -SCIPconvertRealToInt(scip, -realconstant);
1172  else
1173  (*constant) = SCIPconvertRealToInt(scip, realconstant);
1174 
1175  if( realscalar < 0.0 )
1176  (*scalar) = -SCIPconvertRealToInt(scip, -realscalar);
1177  else
1178  (*scalar) = SCIPconvertRealToInt(scip, realscalar);
1179  }
1180  else
1181  {
1182  (*scalar) = 1;
1183  (*constant) = 0;
1184  }
1185 
1186  assert(*scalar != 0);
1187 
1188  return SCIP_OKAY;
1189 }
1190 
1191 /** computes the total energy of all jobs */
1192 static
1194  int* durations, /**< array of job durations */
1195  int* demands, /**< array of job demands */
1196  int njobs /**< number of jobs */
1197  )
1198 {
1199  SCIP_Longint energy;
1200  int j;
1201 
1202  energy = 0;
1203 
1204  for( j = 0; j < njobs; ++j )
1205  energy += (SCIP_Longint) durations[j] * demands[j];
1206 
1207  return energy;
1208 }
1209 
1210 /**@} */
1211 
1212 /**@name Default method to solve a cumulative condition
1213  *
1214  * @{
1215  */
1216 
1217 /** setup and solve subscip to solve single cumulative condition */
1218 static
1220  SCIP* subscip, /**< subscip data structure */
1221  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
1222  int* durations, /**< array of durations */
1223  int* demands, /**< array of demands */
1224  int njobs, /**< number of jobs (activities) */
1225  int capacity, /**< cumulative capacity */
1226  int hmin, /**< left bound of time axis to be considered (including hmin) */
1227  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1228  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes (-1: no limit) */
1229  SCIP_Real timelimit, /**< time limit for solving in seconds */
1230  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
1231  SCIP_Real* ests, /**< array of earliest start times for each job */
1232  SCIP_Real* lsts, /**< array of latest start times for each job */
1233  SCIP_Bool* infeasible, /**< pointer to store if the subproblem was infeasible */
1234  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
1235  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
1236  SCIP_Bool* error /**< pointer to store if an error occurred */
1237  )
1238 {
1239  SCIP_VAR** subvars;
1240  SCIP_CONS* cons;
1241 
1242  char name[SCIP_MAXSTRLEN];
1243  int v;
1244  SCIP_RETCODE retcode;
1245 
1246  assert(subscip != NULL);
1247 
1248  /* copy all plugins */
1250 
1251  /* create the subproblem */
1252  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1253 
1254  SCIP_CALL( SCIPallocBlockMemoryArray(subscip, &subvars, njobs) );
1255 
1256  /* create for each job a start time variable */
1257  for( v = 0; v < njobs; ++v )
1258  {
1259  SCIP_Real objval;
1260 
1261  /* construct variable name */
1262  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
1263 
1264  if( objvals == NULL )
1265  objval = 0.0;
1266  else
1267  objval = objvals[v];
1268 
1269  SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
1270  SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
1271  }
1272 
1273  /* create cumulative constraint */
1274  SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
1275  njobs, subvars, durations, demands, capacity) );
1276 
1277  /* set effective horizon */
1278  SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
1279  SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
1280 
1281  /* add cumulative constraint */
1282  SCIP_CALL( SCIPaddCons(subscip, cons) );
1283  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1284 
1285  /* set CP solver settings
1286  *
1287  * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
1288  * time limit.
1289  */
1291 
1292  /* do not abort subproblem on CTRL-C */
1293  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1294 
1295  /* disable output to console */
1296  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1297 
1298  /* set limits for the subproblem */
1299  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1300  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1301  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1302 
1303  /* forbid recursive call of heuristics and separators solving subMIPs */
1304  SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
1305 
1306  /* solve single cumulative constraint by branch and bound */
1307  retcode = SCIPsolve(subscip);
1308 
1309  if( retcode != SCIP_OKAY )
1310  (*error) = TRUE;
1311  else
1312  {
1313  SCIPdebugMsg(subscip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1314 
1315  /* evaluated solution status */
1316  switch( SCIPgetStatus(subscip) )
1317  {
1318  case SCIP_STATUS_INFORUNBD:
1320  (*infeasible) = TRUE;
1321  (*solved) = TRUE;
1322  break;
1323  case SCIP_STATUS_UNBOUNDED:
1324  (*unbounded) = TRUE;
1325  (*solved) = TRUE;
1326  break;
1327  case SCIP_STATUS_OPTIMAL:
1328  {
1329  SCIP_SOL* sol;
1330  SCIP_Real solval;
1331 
1332  sol = SCIPgetBestSol(subscip);
1333  assert(sol != NULL);
1334 
1335  for( v = 0; v < njobs; ++v )
1336  {
1337  solval = SCIPgetSolVal(subscip, sol, subvars[v]);
1338 
1339  ests[v] = solval;
1340  lsts[v] = solval;
1341  }
1342  (*solved) = TRUE;
1343  break;
1344  }
1345  case SCIP_STATUS_NODELIMIT:
1347  case SCIP_STATUS_TIMELIMIT:
1348  case SCIP_STATUS_MEMLIMIT:
1350  case SCIP_STATUS_TERMINATE:
1351  /* transfer the global bound changes */
1352  for( v = 0; v < njobs; ++v )
1353  {
1354  ests[v] = SCIPvarGetLbGlobal(subvars[v]);
1355  lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
1356  }
1357  (*solved) = FALSE;
1358  break;
1359 
1360  case SCIP_STATUS_UNKNOWN:
1362  case SCIP_STATUS_GAPLIMIT:
1363  case SCIP_STATUS_SOLLIMIT:
1366  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1367  return SCIP_INVALIDDATA;
1368  }
1369  }
1370 
1371  /* release all variables */
1372  for( v = 0; v < njobs; ++v )
1373  {
1374  SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1375  }
1376 
1377  SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
1378 
1379  return SCIP_OKAY;
1380 }
1381 
1382 /** solve single cumulative condition using SCIP and a single cumulative constraint */
1383 static
1384 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1386  SCIP* subscip;
1387 
1388  SCIP_RETCODE retcode;
1389 
1390  assert(njobs > 0);
1391 
1392  (*solved) = FALSE;
1393  (*infeasible) = FALSE;
1394  (*unbounded) = FALSE;
1395  (*error) = FALSE;
1396 
1397  SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1398 
1399  /* initialize the sub-problem */
1400  SCIP_CALL( SCIPcreate(&subscip) );
1401 
1402  /* create and solve the subproblem. catch possible errors */
1403  retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
1404  njobs, capacity, hmin, hmax,
1405  maxnodes, timelimit, memorylimit,
1406  ests, lsts,
1407  infeasible, unbounded, solved, error);
1408 
1409  /* free the subscip in any case */
1410  SCIP_CALL( SCIPfree(&subscip) );
1411 
1412  SCIP_CALL( retcode );
1413 
1414  return SCIP_OKAY;
1415 }
1416 
1417 #if 0
1418 /** solve single cumulative condition using SCIP and the time indexed formulation */
1419 static
1420 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1421 {
1422  SCIP* subscip;
1423  SCIP_VAR*** binvars;
1424  SCIP_RETCODE retcode;
1425  char name[SCIP_MAXSTRLEN];
1426  int minest;
1427  int maxlct;
1428  int t;
1429  int v;
1430 
1431  assert(njobs > 0);
1432 
1433  (*solved) = FALSE;
1434  (*infeasible) = FALSE;
1435  (*unbounded) = FALSE;
1436  (*error) = FALSE;
1437 
1438  SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
1439 
1440  /* initialize the sub-problem */
1441  SCIP_CALL( SCIPcreate(&subscip) );
1442 
1443  /* copy all plugins */
1445 
1446  /* create the subproblem */
1447  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1448 
1449  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
1450 
1451  minest = INT_MAX;
1452  maxlct = INT_MIN;
1453 
1454  /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1455  * partitioning constrain which forces that job starts
1456  */
1457  for( v = 0; v < njobs; ++v )
1458  {
1459  SCIP_CONS* cons;
1460  SCIP_Real objval;
1461  int timeinterval;
1462  int est;
1463  int lst;
1464 
1465  if( objvals == NULL )
1466  objval = 0.0;
1467  else
1468  objval = objvals[v];
1469 
1470  est = ests[v];
1471  lst = lsts[v];
1472 
1473  /* compute number of possible start points */
1474  timeinterval = lst - est + 1;
1475  assert(timeinterval > 0);
1476 
1477  /* compute the smallest earliest start time and largest latest completion time */
1478  minest = MIN(minest, est);
1479  maxlct = MAX(maxlct, lst + durations[v]);
1480 
1481  /* construct constraint name */
1482  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1483 
1484  SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1485 
1486  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
1487 
1488  for( t = 0; t < timeinterval; ++t )
1489  {
1490  SCIP_VAR* binvar;
1491 
1492  /* construct varibale name */
1493  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1494 
1495  SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1496  SCIP_CALL( SCIPaddVar(subscip, binvar) );
1497 
1498  /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1499  SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1500 
1501  binvars[v][t] = binvar;
1502  }
1503 
1504  /* add and release the set partitioning constraint */
1505  SCIP_CALL( SCIPaddCons(subscip, cons) );
1506  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1507  }
1508 
1509  /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1510  hmin = MAX(hmin, minest);
1511  hmax = MIN(hmax, maxlct);
1512  assert(hmin > INT_MIN);
1513  assert(hmax < INT_MAX);
1514  assert(hmin < hmax);
1515 
1516  /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1517  for( t = hmin; t < hmax; ++t )
1518  {
1519  SCIP_CONS* cons;
1520 
1521  /* construct constraint name */
1522  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1523 
1524  /* create an empty knapsack constraint */
1525  SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1526 
1527  /* add all jobs which potentially can be processed at that time point */
1528  for( v = 0; v < njobs; ++v )
1529  {
1530  int duration;
1531  int demand;
1532  int start;
1533  int end;
1534  int est;
1535  int lst;
1536  int k;
1537 
1538  est = ests[v];
1539  lst = lsts[v] ;
1540 
1541  duration = durations[v];
1542  assert(duration > 0);
1543 
1544  /* check if the varibale is processed potentially at time point t */
1545  if( t < est || t >= lst + duration )
1546  continue;
1547 
1548  demand = demands[v];
1549  assert(demand >= 0);
1550 
1551  start = MAX(t - duration + 1, est);
1552  end = MIN(t, lst);
1553 
1554  assert(start <= end);
1555 
1556  for( k = start; k <= end; ++k )
1557  {
1558  assert(binvars[v][k] != NULL);
1559  SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1560  }
1561  }
1562 
1563  /* add and release the knapsack constraint */
1564  SCIP_CALL( SCIPaddCons(subscip, cons) );
1565  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1566  }
1567 
1568  /* do not abort subproblem on CTRL-C */
1569  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1570 
1571  /* disable output to console */
1572  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1573 
1574  /* set limits for the subproblem */
1575  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1576  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1577  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1578 
1579  /* solve single cumulative constraint by branch and bound */
1580  retcode = SCIPsolve(subscip);
1581 
1582  if( retcode != SCIP_OKAY )
1583  (*error) = TRUE;
1584  else
1585  {
1586  SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1587 
1588  /* evaluated solution status */
1589  switch( SCIPgetStatus(subscip) )
1590  {
1591  case SCIP_STATUS_INFORUNBD:
1593  (*infeasible) = TRUE;
1594  (*solved) = TRUE;
1595  break;
1596  case SCIP_STATUS_UNBOUNDED:
1597  (*unbounded) = TRUE;
1598  (*solved) = TRUE;
1599  break;
1600  case SCIP_STATUS_OPTIMAL:
1601  {
1602  SCIP_SOL* sol;
1603 
1604  sol = SCIPgetBestSol(subscip);
1605  assert(sol != NULL);
1606 
1607  for( v = 0; v < njobs; ++v )
1608  {
1609  int timeinterval;
1610  int est;
1611  int lst;
1612 
1613  est = ests[v];
1614  lst = lsts[v];
1615 
1616  /* compute number of possible start points */
1617  timeinterval = lst - est + 1;
1618 
1619  /* check which binary varibale is set to one */
1620  for( t = 0; t < timeinterval; ++t )
1621  {
1622  if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1623  {
1624  ests[v] = est + t;
1625  lsts[v] = est + t;
1626  break;
1627  }
1628  }
1629  }
1630 
1631  (*solved) = TRUE;
1632  break;
1633  }
1634  case SCIP_STATUS_NODELIMIT:
1636  case SCIP_STATUS_TIMELIMIT:
1637  case SCIP_STATUS_MEMLIMIT:
1639  /* transfer the global bound changes */
1640  for( v = 0; v < njobs; ++v )
1641  {
1642  int timeinterval;
1643  int est;
1644  int lst;
1645 
1646  est = ests[v];
1647  lst = lsts[v];
1648 
1649  /* compute number of possible start points */
1650  timeinterval = lst - est + 1;
1651 
1652  /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1653  for( t = 0; t < timeinterval; ++t )
1654  {
1655  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1656  {
1657  ests[v] = est + t;
1658  break;
1659  }
1660  }
1661 
1662  /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1663  for( t = timeinterval - 1; t >= 0; --t )
1664  {
1665  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1666  {
1667  lsts[v] = est + t;
1668  break;
1669  }
1670  }
1671  }
1672  (*solved) = FALSE;
1673  break;
1674 
1675  case SCIP_STATUS_UNKNOWN:
1677  case SCIP_STATUS_GAPLIMIT:
1678  case SCIP_STATUS_SOLLIMIT:
1680  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1681  return SCIP_INVALIDDATA;
1682  }
1683  }
1684 
1685  /* release all variables */
1686  for( v = 0; v < njobs; ++v )
1687  {
1688  int timeinterval;
1689  int est;
1690  int lst;
1691 
1692  est = ests[v];
1693  lst = lsts[v];
1694 
1695  /* compute number of possible start points */
1696  timeinterval = lst - est + 1;
1697 
1698  for( t = 0; t < timeinterval; ++t )
1699  {
1700  SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1701  }
1702  SCIPfreeBufferArray(subscip, &binvars[v]);
1703  }
1704 
1705  SCIPfreeBufferArray(subscip, &binvars);
1706 
1707  SCIP_CALL( SCIPfree(&subscip) );
1708 
1709  return SCIP_OKAY;
1710 }
1711 #endif
1712 
1713 /**@} */
1714 
1715 /**@name Constraint handler data
1716  *
1717  * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1718  * handler.
1719  *
1720  * @{
1721  */
1722 
1723 /** creates constaint handler data for cumulative constraint handler */
1724 static
1726  SCIP* scip, /**< SCIP data structure */
1727  SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1728  SCIP_EVENTHDLR* eventhdlr /**< event handler */
1729  )
1730 {
1731  /* create precedence constraint handler data */
1732  assert(scip != NULL);
1733  assert(conshdlrdata != NULL);
1734  assert(eventhdlr != NULL);
1735 
1736  SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
1737 
1738  /* set event handler for checking if bounds of start time variables are tighten */
1739  (*conshdlrdata)->eventhdlr = eventhdlr;
1740 
1741  /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1742  (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1743 
1744 #ifdef SCIP_STATISTIC
1745  (*conshdlrdata)->nlbtimetable = 0;
1746  (*conshdlrdata)->nubtimetable = 0;
1747  (*conshdlrdata)->ncutofftimetable = 0;
1748  (*conshdlrdata)->nlbedgefinder = 0;
1749  (*conshdlrdata)->nubedgefinder = 0;
1750  (*conshdlrdata)->ncutoffedgefinder = 0;
1751  (*conshdlrdata)->ncutoffoverload = 0;
1752  (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1753 
1754  (*conshdlrdata)->nirrelevantjobs = 0;
1755  (*conshdlrdata)->nalwaysruns = 0;
1756  (*conshdlrdata)->nremovedlocks = 0;
1757  (*conshdlrdata)->ndualfixs = 0;
1758  (*conshdlrdata)->ndecomps = 0;
1759  (*conshdlrdata)->ndualbranchs = 0;
1760  (*conshdlrdata)->nallconsdualfixs = 0;
1761  (*conshdlrdata)->naddedvarbounds = 0;
1762  (*conshdlrdata)->naddeddisjunctives = 0;
1763 #endif
1764 
1765  return SCIP_OKAY;
1766 }
1767 
1768 /** frees constraint handler data for logic or constraint handler */
1769 static
1770 void conshdlrdataFree(
1771  SCIP* scip, /**< SCIP data structure */
1772  SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1773  )
1774 {
1775  assert(conshdlrdata != NULL);
1776  assert(*conshdlrdata != NULL);
1777 
1778  SCIPfreeBlockMemory(scip, conshdlrdata);
1779 }
1780 
1781 /**@} */
1782 
1783 
1784 /**@name Constraint data methods
1785  *
1786  * @{
1787  */
1788 
1789 /** catches bound change events for all variables in transformed cumulative constraint */
1790 static
1792  SCIP* scip, /**< SCIP data structure */
1793  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1794  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1795  )
1796 {
1797  int v;
1798 
1799  assert(scip != NULL);
1800  assert(consdata != NULL);
1801  assert(eventhdlr != NULL);
1802 
1803  /* catch event for every single variable */
1804  for( v = 0; v < consdata->nvars; ++v )
1805  {
1806  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1807  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1808  }
1809 
1810  return SCIP_OKAY;
1811 }
1812 
1813 /** drops events for variable at given position */
1814 static
1816  SCIP* scip, /**< SCIP data structure */
1817  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1818  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1819  int pos /**< array position of variable to catch bound change events for */
1820  )
1821 {
1822  assert(scip != NULL);
1823  assert(consdata != NULL);
1824  assert(eventhdlr != NULL);
1825  assert(0 <= pos && pos < consdata->nvars);
1826  assert(consdata->vars[pos] != NULL);
1827 
1828  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1829  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1830 
1831  return SCIP_OKAY;
1832 }
1833 
1834 /** drops bound change events for all variables in transformed linear constraint */
1835 static
1837  SCIP* scip, /**< SCIP data structure */
1838  SCIP_CONSDATA* consdata, /**< linear constraint data */
1839  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1840  )
1841 {
1842  int v;
1843 
1844  assert(scip != NULL);
1845  assert(consdata != NULL);
1846 
1847  /* drop event of every single variable */
1848  for( v = 0; v < consdata->nvars; ++v )
1849  {
1850  SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1851  }
1852 
1853  return SCIP_OKAY;
1854 }
1855 
1856 /** initialize variable lock data structure */
1857 static
1858 void initializeLocks(
1859  SCIP_CONSDATA* consdata, /**< constraint data */
1860  SCIP_Bool locked /**< should the variable be locked? */
1861  )
1862 {
1863  int nvars;
1864  int v;
1865 
1866  nvars = consdata->nvars;
1867 
1868  /* initialize locking arrays */
1869  for( v = 0; v < nvars; ++v )
1870  {
1871  consdata->downlocks[v] = locked;
1872  consdata->uplocks[v] = locked;
1873  }
1874 }
1875 
1876 /** creates constraint data of cumulative constraint */
1877 static
1879  SCIP* scip, /**< SCIP data structure */
1880  SCIP_CONSDATA** consdata, /**< pointer to consdata */
1881  SCIP_VAR** vars, /**< array of integer variables */
1882  SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1883  int* durations, /**< array containing corresponding durations */
1884  int* demands, /**< array containing corresponding demands */
1885  int nvars, /**< number of variables */
1886  int capacity, /**< available cumulative capacity */
1887  int hmin, /**< left bound of time axis to be considered (including hmin) */
1888  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1889  SCIP_Bool check /**< is the corresponding constraint a check constraint */
1890  )
1891 {
1892  int v;
1893 
1894  assert(scip != NULL);
1895  assert(consdata != NULL);
1896  assert(vars != NULL || nvars > 0);
1897  assert(demands != NULL);
1898  assert(durations != NULL);
1899  assert(capacity >= 0);
1900  assert(hmin >= 0);
1901  assert(hmin < hmax);
1902 
1903  /* create constraint data */
1904  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1905 
1906  (*consdata)->hmin = hmin;
1907  (*consdata)->hmax = hmax;
1908 
1909  (*consdata)->capacity = capacity;
1910  (*consdata)->demandrows = NULL;
1911  (*consdata)->demandrowssize = 0;
1912  (*consdata)->ndemandrows = 0;
1913  (*consdata)->scoverrows = NULL;
1914  (*consdata)->nscoverrows = 0;
1915  (*consdata)->scoverrowssize = 0;
1916  (*consdata)->bcoverrows = NULL;
1917  (*consdata)->nbcoverrows = 0;
1918  (*consdata)->bcoverrowssize = 0;
1919  (*consdata)->nvars = nvars;
1920  (*consdata)->varssize = nvars;
1921  (*consdata)->signature = 0;
1922  (*consdata)->validsignature = FALSE;
1923  (*consdata)->normalized = FALSE;
1924  (*consdata)->covercuts = FALSE;
1925  (*consdata)->propagated = FALSE;
1926  (*consdata)->varbounds = FALSE;
1927  (*consdata)->triedsolving = FALSE;
1928 
1929  if( nvars > 0 )
1930  {
1931  assert(vars != NULL); /* for flexelint */
1932 
1933  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1934  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1935  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1936  (*consdata)->linkingconss = NULL;
1937 
1938  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1939  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1940 
1941  /* initialize variable lock data structure; the locks are only used if the contraint is a check constraint */
1942  initializeLocks(*consdata, check);
1943 
1944  if( linkingconss != NULL )
1945  {
1946  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
1947  }
1948 
1949  /* transform variables, if they are not yet transformed */
1950  if( SCIPisTransformed(scip) )
1951  {
1952  SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
1953 
1954  /* get transformed variables and do NOT captures these */
1955  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1956 
1957  /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
1958  * been multi-aggregated
1959  */
1960  for( v = 0; v < nvars; ++v )
1961  {
1962  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
1963  }
1964 
1965  if( linkingconss != NULL )
1966  {
1967  /* get transformed constraints and captures these */
1968  SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
1969 
1970  for( v = 0; v < nvars; ++v )
1971  assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
1972  }
1973  }
1974  }
1975  else
1976  {
1977  (*consdata)->vars = NULL;
1978  (*consdata)->downlocks = NULL;
1979  (*consdata)->uplocks = NULL;
1980  (*consdata)->demands = NULL;
1981  (*consdata)->durations = NULL;
1982  (*consdata)->linkingconss = NULL;
1983  }
1984 
1985  /* initialize values for running propagation algorithms efficiently */
1986  (*consdata)->resstrength1 = -1.0;
1987  (*consdata)->resstrength2 = -1.0;
1988  (*consdata)->cumfactor1 = -1.0;
1989  (*consdata)->disjfactor1 = -1.0;
1990  (*consdata)->disjfactor2 = -1.0;
1991  (*consdata)->estimatedstrength = -1.0;
1992 
1993  SCIPstatistic( (*consdata)->maxpeak = -1 );
1994 
1995  return SCIP_OKAY;
1996 }
1997 
1998 /** releases LP rows of constraint data and frees rows array */
1999 static
2001  SCIP* scip, /**< SCIP data structure */
2002  SCIP_CONSDATA** consdata /**< constraint data */
2003  )
2004 {
2005  int r;
2006 
2007  assert(consdata != NULL);
2008  assert(*consdata != NULL);
2009 
2010  for( r = 0; r < (*consdata)->ndemandrows; ++r )
2011  {
2012  assert((*consdata)->demandrows[r] != NULL);
2013  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
2014  }
2015 
2016  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
2017 
2018  (*consdata)->ndemandrows = 0;
2019  (*consdata)->demandrowssize = 0;
2020 
2021  /* free rows of cover cuts */
2022  for( r = 0; r < (*consdata)->nscoverrows; ++r )
2023  {
2024  assert((*consdata)->scoverrows[r] != NULL);
2025  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
2026  }
2027 
2028  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
2029 
2030  (*consdata)->nscoverrows = 0;
2031  (*consdata)->scoverrowssize = 0;
2032 
2033  for( r = 0; r < (*consdata)->nbcoverrows; ++r )
2034  {
2035  assert((*consdata)->bcoverrows[r] != NULL);
2036  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2037  }
2038 
2039  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2040 
2041  (*consdata)->nbcoverrows = 0;
2042  (*consdata)->bcoverrowssize = 0;
2043 
2044  (*consdata)->covercuts = FALSE;
2045 
2046  return SCIP_OKAY;
2047 }
2048 
2049 /** frees a cumulative constraint data */
2050 static
2052  SCIP* scip, /**< SCIP data structure */
2053  SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2054  )
2055 {
2056  int varssize;
2057  int nvars;
2058 
2059  assert(consdata != NULL);
2060  assert(*consdata != NULL);
2061 
2062  nvars = (*consdata)->nvars;
2063  varssize = (*consdata)->varssize;
2064 
2065  if( varssize > 0 )
2066  {
2067  int v;
2068 
2069  /* release and free the rows */
2070  SCIP_CALL( consdataFreeRows(scip, consdata) );
2071 
2072  /* release the linking constraints if they were generated */
2073  if( (*consdata)->linkingconss != NULL )
2074  {
2075  for( v = nvars-1; v >= 0; --v )
2076  {
2077  assert((*consdata)->linkingconss[v] != NULL );
2078  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2079  }
2080 
2081  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2082  }
2083 
2084  /* free arrays */
2085  SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2086  SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2087  SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2088  SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2089  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2090  }
2091 
2092  /* free memory */
2093  SCIPfreeBlockMemory(scip, consdata);
2094 
2095  return SCIP_OKAY;
2096 }
2097 
2098 /** prints cumulative constraint to file stream */
2099 static
2100 void consdataPrint(
2101  SCIP* scip, /**< SCIP data structure */
2102  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2103  FILE* file /**< output file (or NULL for standard output) */
2104  )
2105 {
2106  int v;
2107 
2108  assert(consdata != NULL);
2109 
2110  /* print coefficients */
2111  SCIPinfoMessage( scip, file, "cumulative(");
2112 
2113  for( v = 0; v < consdata->nvars; ++v )
2114  {
2115  assert(consdata->vars[v] != NULL);
2116  if( v > 0 )
2117  SCIPinfoMessage(scip, file, ", ");
2118  SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2119  SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2120  consdata->durations[v], consdata->demands[v]);
2121  }
2122  SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2123 }
2124 
2125 /** deletes coefficient at given position from constraint data */
2126 static
2128  SCIP* scip, /**< SCIP data structure */
2129  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2130  SCIP_CONS* cons, /**< knapsack constraint */
2131  int pos /**< position of coefficient to delete */
2132  )
2133 {
2134  SCIP_CONSHDLR* conshdlr;
2135  SCIP_CONSHDLRDATA* conshdlrdata;
2136 
2137  assert(scip != NULL);
2138  assert(consdata != NULL);
2139  assert(cons != NULL);
2140  assert(SCIPconsIsTransformed(cons));
2141  assert(!SCIPinProbing(scip));
2142 
2143  SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2144  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2145 
2146  /* remove the rounding locks for the deleted variable */
2147  SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2148 
2149  consdata->downlocks[pos] = FALSE;
2150  consdata->uplocks[pos] = FALSE;
2151 
2152  if( consdata->linkingconss != NULL )
2153  {
2154  SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2155  }
2156 
2157  /* get event handler */
2158  conshdlr = SCIPconsGetHdlr(cons);
2159  assert(conshdlr != NULL);
2160  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2161  assert(conshdlrdata != NULL);
2162  assert(conshdlrdata->eventhdlr != NULL);
2163 
2164  /* drop events */
2165  SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2166 
2167  SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2168  SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2169 
2170  /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2171  * position
2172  */
2173  if( pos != consdata->nvars - 1 )
2174  {
2175  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2176  consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2177  consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2178  consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2179  consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2180 
2181  if( consdata->linkingconss != NULL )
2182  {
2183  consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2184  }
2185  }
2186 
2187  consdata->nvars--;
2188  consdata->validsignature = FALSE;
2189  consdata->normalized = FALSE;
2190 
2191  return SCIP_OKAY;
2192 }
2193 
2194 /** collect linking constraints for each integer variable */
2195 static
2197  SCIP* scip, /**< SCIP data structure */
2198  SCIP_CONSDATA* consdata /**< pointer to consdata */
2199  )
2200 {
2201  int nvars;
2202  int v;
2203 
2204  assert(scip != NULL);
2205  assert(consdata != NULL);
2206 
2207  nvars = consdata->nvars;
2208  assert(nvars > 0);
2209  assert(consdata->linkingconss == NULL);
2210 
2211  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2212 
2213  for( v = 0; v < nvars; ++v )
2214  {
2215  SCIP_CONS* cons;
2216  SCIP_VAR* var;
2217 
2218  var = consdata->vars[v];
2219  assert(var != NULL);
2220 
2221  SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2222 
2223  /* create linking constraint if it does not exist yet */
2224  if( !SCIPexistsConsLinking(scip, var) )
2225  {
2226  char name[SCIP_MAXSTRLEN];
2227 
2228  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2229 
2230  /* creates and captures an linking constraint */
2231  SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2232  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2233  SCIP_CALL( SCIPaddCons(scip, cons) );
2234  consdata->linkingconss[v] = cons;
2235  }
2236  else
2237  {
2238  consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2239  SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2240  }
2241 
2242  assert(SCIPexistsConsLinking(scip, var));
2243  assert(consdata->linkingconss[v] != NULL);
2244  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2245  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2246  }
2247 
2248  return SCIP_OKAY;
2249 }
2250 
2251 /**@} */
2252 
2253 
2254 /**@name Check methods
2255  *
2256  * @{
2257  */
2258 
2259 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2260  * given solution is satisfied
2261  */
2262 static
2264  SCIP* scip, /**< SCIP data structure */
2265  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2266  int nvars, /**< number of variables (jobs) */
2267  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2268  int* durations, /**< array containing corresponding durations */
2269  int* demands, /**< array containing corresponding demands */
2270  int capacity, /**< available cumulative capacity */
2271  int hmin, /**< left bound of time axis to be considered (including hmin) */
2272  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2273  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2274  SCIP_CONS* cons, /**< constraint which is checked */
2275  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2276  )
2277 {
2278  int* startsolvalues; /* stores when each job is starting */
2279  int* endsolvalues; /* stores when each job ends */
2280  int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2281  int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2282 
2283  int freecapacity;
2284  int curtime; /* point in time which we are just checking */
2285  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2286  int j;
2287 
2288  SCIP_Real absviol;
2289  SCIP_Real relviol;
2290 
2291  assert(scip != NULL);
2292  assert(violated != NULL);
2293 
2294  (*violated) = FALSE;
2295 
2296  if( nvars == 0 )
2297  return SCIP_OKAY;
2298 
2299  assert(vars != NULL);
2300  assert(demands != NULL);
2301  assert(durations != NULL);
2302 
2303  /* compute time points where we have to check whether capacity constraint is infeasible or not */
2304  SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2305  SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2306  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2307  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2308 
2309  /* assign variables, start and endpoints to arrays */
2310  for ( j = 0; j < nvars; ++j )
2311  {
2312  int solvalue;
2313 
2314  /* the constraint of the cumulative constraint handler should be called after the integrality check */
2315  assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2316 
2317  solvalue = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2318 
2319  /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2320  * jobs which start before hmin to hmin
2321  */
2322  startsolvalues[j] = MAX(solvalue, hmin);
2323  startindices[j] = j;
2324 
2325  endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2326  endindices[j] = j;
2327  }
2328 
2329  /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2330  * corresponding indices in the same way)
2331  */
2332  SCIPsortIntInt(startsolvalues, startindices, nvars);
2333  SCIPsortIntInt(endsolvalues, endindices, nvars);
2334 
2335  endindex = 0;
2336  freecapacity = capacity;
2337  absviol = 0.0;
2338  relviol = 0.0;
2339 
2340  /* check each start point of a job whether the capacity is kept or not */
2341  for( j = 0; j < nvars; ++j )
2342  {
2343  /* only check intervals [hmin,hmax) */
2344  curtime = startsolvalues[j];
2345 
2346  if( curtime >= hmax )
2347  break;
2348 
2349  /* subtract all capacity needed up to this point */
2350  freecapacity -= demands[startindices[j]];
2351  while( j+1 < nvars && startsolvalues[j+1] == curtime )
2352  {
2353  j++;
2354  freecapacity -= demands[startindices[j]];
2355  }
2356 
2357  /* free all capacity usages of jobs that are no longer running */
2358  while( endindex < nvars && curtime >= endsolvalues[endindex] )
2359  {
2360  freecapacity += demands[endindices[endindex]];
2361  ++endindex;
2362  }
2363  assert(freecapacity <= capacity);
2364 
2365  /* update absolute and relative violation */
2366  if( absviol < (SCIP_Real) (-freecapacity) )
2367  {
2368  absviol = -freecapacity;
2369  relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
2370  }
2371 
2372  /* check freecapacity to be smaller than zero */
2373  if( freecapacity < 0 && curtime >= hmin )
2374  {
2375  SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2376  (*violated) = TRUE;
2377 
2378  if( printreason )
2379  {
2380  int i;
2381 
2382  /* first state the violated constraints */
2383  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2384 
2385  /* second state the reason */
2386  SCIPinfoMessage(scip, NULL,
2387  ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2388  curtime, capacity, capacity - freecapacity);
2389 
2390  for( i = 0; i <= j; ++i )
2391  {
2392  if( startsolvalues[i] + durations[startindices[i]] > curtime )
2393  {
2394  SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2395  SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2396  demands[startindices[i]]);
2397  }
2398  }
2399  }
2400  break;
2401  }
2402  } /*lint --e{850}*/
2403 
2404  /* update constraint violation in solution */
2405  if( sol != NULL )
2406  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
2407 
2408  /* free all buffer arrays */
2409  SCIPfreeBufferArray(scip, &endindices);
2410  SCIPfreeBufferArray(scip, &startindices);
2411  SCIPfreeBufferArray(scip, &endsolvalues);
2412  SCIPfreeBufferArray(scip, &startsolvalues);
2413 
2414  return SCIP_OKAY;
2415 }
2416 
2417 /** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2418  * least zero or not. If not (*violated) is set to TRUE
2419  */
2420 static
2422  SCIP* scip, /**< SCIP data structure */
2423  SCIP_CONS* cons, /**< constraint to be checked */
2424  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2425  SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2426  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2427  )
2428 {
2429  SCIP_CONSDATA* consdata;
2430 
2431  assert(scip != NULL);
2432  assert(cons != NULL);
2433  assert(violated != NULL);
2434 
2435  SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2436 
2437  consdata = SCIPconsGetData(cons);
2438  assert(consdata != NULL);
2439 
2440  /* check the cumulative condition */
2441  SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2442  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2443  violated, cons, printreason) );
2444 
2445  return SCIP_OKAY;
2446 }
2447 
2448 /**@} */
2449 
2450 /**@name Conflict analysis
2451  *
2452  * @{
2453  */
2454 
2455 /** resolves the propagation of the core time algorithm */
2456 static
2458  SCIP* scip, /**< SCIP data structure */
2459  int nvars, /**< number of start time variables (activities) */
2460  SCIP_VAR** vars, /**< array of start time variables */
2461  int* durations, /**< array of durations */
2462  int* demands, /**< array of demands */
2463  int capacity, /**< cumulative capacity */
2464  int hmin, /**< left bound of time axis to be considered (including hmin) */
2465  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2466  SCIP_VAR* infervar, /**< inference variable */
2467  int inferdemand, /**< demand of the inference variable */
2468  int inferpeak, /**< time point which causes the propagation */
2469  int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2470  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2471  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2472  int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2473  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2474  )
2475 {
2476  SCIP_VAR* var;
2477  SCIP_Bool* reported;
2478  int duration;
2479  int maxlst;
2480  int minect;
2481  int ect;
2482  int lst;
2483  int j;
2484 
2485  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
2486 
2487  SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2488  SCIPvarGetName(infervar), inferdemand, inferpeak);
2489  assert(nvars > 0);
2490 
2491  /* adjusted capacity */
2492  capacity -= inferdemand;
2493  maxlst = INT_MIN;
2494  minect = INT_MAX;
2495 
2496  SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2497  BMSclearMemoryArray(reported, nvars);
2498 
2499  /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2500  * inference peak and those where the current conflict bounds provide a core at the inference peak
2501  */
2502  for( j = 0; j < nvars && capacity >= 0; ++j )
2503  {
2504  var = vars[j];
2505  assert(var != NULL);
2506 
2507  /* skip inference variable */
2508  if( var == infervar )
2509  continue;
2510 
2511  duration = durations[j];
2512  assert(duration > 0);
2513 
2514  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2515  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2516  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2517  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2518  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2519 
2520  SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2522  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2523 
2524  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2525  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2526 
2527  /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2528  * that job without adding it the explanation
2529  */
2530  if( inferpeak < ect && lst <= inferpeak )
2531  {
2532  capacity -= demands[j];
2533  reported[j] = TRUE;
2534 
2535  maxlst = MAX(maxlst, lst);
2536  minect = MIN(minect, ect);
2537  assert(maxlst < minect);
2538 
2539  if( explanation != NULL )
2540  explanation[j] = TRUE;
2541 
2542  continue;
2543  }
2544 
2545  /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2546  * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2547  * not part of the conflict yet we get the global bounds back.
2548  */
2549  ect = SCIPconvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2550  lst = SCIPconvertRealToInt(scip, SCIPgetConflictVarUb(scip, var));
2551 
2552  /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2553  * of that job without and collect the job as part of the explanation
2554  *
2555  * @note we do not need to reported that job to SCIP since the required bounds are already reported
2556  */
2557  if( inferpeak < ect && lst <= inferpeak )
2558  {
2559  capacity -= demands[j];
2560  reported[j] = TRUE;
2561 
2562  maxlst = MAX(maxlst, lst);
2563  minect = MIN(minect, ect);
2564  assert(maxlst < minect);
2565 
2566  if( explanation != NULL )
2567  explanation[j] = TRUE;
2568  }
2569  }
2570 
2571  if( capacity >= 0 )
2572  {
2573  int* cands;
2574  int* canddemands;
2575  int ncands;
2576  int c;
2577 
2578  SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2579  SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2580  ncands = 0;
2581 
2582  /* collect all cores of the variables which lay in the considered time window except the inference variable */
2583  for( j = 0; j < nvars; ++j )
2584  {
2585  var = vars[j];
2586  assert(var != NULL);
2587 
2588  /* skip inference variable */
2589  if( var == infervar || reported[j] )
2590  continue;
2591 
2592  duration = durations[j];
2593  assert(duration > 0);
2594 
2595  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2596  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2597  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2598  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2599  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2600 
2601  /* collect local core information */
2602  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2603  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2604 
2605  SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2606  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2607  SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2608 
2609  /* check if the inference peak is part of the core */
2610  if( inferpeak < ect && lst <= inferpeak )
2611  {
2612  cands[ncands] = j;
2613  canddemands[ncands] = demands[j];
2614  ncands++;
2615 
2616  capacity -= demands[j];
2617  }
2618  }
2619 
2620  /* sort candidates indices w.r.t. their demands */
2621  SCIPsortDownIntInt(canddemands, cands, ncands);
2622 
2623  assert(capacity < 0);
2624  assert(ncands > 0);
2625 
2626  /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2627  while( capacity + canddemands[ncands-1] < 0 )
2628  {
2629  ncands--;
2630  capacity += canddemands[ncands];
2631  assert(ncands > 0);
2632  }
2633 
2634  /* compute the size (number of time steps) of the job cores */
2635  for( c = 0; c < ncands; ++c )
2636  {
2637  var = vars[cands[c]];
2638  assert(var != NULL);
2639 
2640  duration = durations[cands[c]];
2641 
2642  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2643  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2644 
2645  maxlst = MAX(maxlst, lst);
2646  minect = MIN(minect, ect);
2647  assert(maxlst < minect);
2648  }
2649 
2650  SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2651  assert(inferpeak >= maxlst);
2652  assert(inferpeak < minect);
2653 
2654  /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2655  if( relaxedpeak < inferpeak )
2656  {
2657  inferpeak = MAX(maxlst, relaxedpeak);
2658  }
2659  else if( relaxedpeak > inferpeak )
2660  {
2661  inferpeak = MIN(minect-1, relaxedpeak);
2662  }
2663  assert(inferpeak >= hmin);
2664  assert(inferpeak < hmax);
2665  assert(inferpeak >= maxlst);
2666  assert(inferpeak < minect);
2667 
2668  /* post all necessary bound changes */
2669  for( c = 0; c < ncands; ++c )
2670  {
2671  var = vars[cands[c]];
2672  assert(var != NULL);
2673 
2674  if( usebdwidening )
2675  {
2676  duration = durations[cands[c]];
2677 
2678  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2679  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2680  }
2681  else
2682  {
2683  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2684  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2685  }
2686 
2687  if( explanation != NULL )
2688  explanation[cands[c]] = TRUE;
2689  }
2690 
2691  SCIPfreeBufferArray(scip, &canddemands);
2692  SCIPfreeBufferArray(scip, &cands);
2693  }
2694 
2695  SCIPfreeBufferArray(scip, &reported);
2696 
2697  if( provedpeak != NULL )
2698  *provedpeak = inferpeak;
2699 
2700  return SCIP_OKAY;
2701 }
2702 
2703 #if 0
2704 /** repropagation of edge finding algorithm simplified version from Petr Vilim only a small subset is reported such that
2705  * energy in total and for bound change is enough
2706  */
2707 static
2708 SCIP_RETCODE resolvePropagationEdgeFinding(
2709  SCIP* scip, /**< SCIP data structure */
2710  int nvars, /**< number of start time variables (activities) */
2711  SCIP_VAR** vars, /**< array of start time variables */
2712  int* durations, /**< array of durations */
2713  int hmin, /**< left bound of time axis to be considered (including hmin) */
2714  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2715  SCIP_VAR* infervar, /**< variable whose bound change is to be explained */
2716  INFERINFO inferinfo, /**< inference info containing position of correct bdchgids */
2717  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2718  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2719  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2720  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2721  )
2722 {
2723  int est;
2724  int lct;
2725  int j;
2726 
2727  /* ???????????????????? do bound widening */
2728 
2729  assert(scip != NULL);
2730  assert(nvars > 0);
2731  assert(inferInfoGetProprule(inferinfo) == PROPRULE_2_EDGEFINDING);
2732 
2733  SCIPdebugMsg(scip, "repropagate edge-finding with short reasons for variable <%s>\n", SCIPvarGetName(infervar));
2734 
2735  if( boundtype == SCIP_BOUNDTYPE_LOWER )
2736  {
2737  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
2738  }
2739  else
2740  {
2741  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
2742  }
2743 
2744  est = inferInfoGetData1(inferinfo);
2745  lct = inferInfoGetData2(inferinfo);
2746  assert(est < lct);
2747 
2748  /* collect the energies of all variables in [est_omega, lct_omega] */
2749  for( j = 0; j < nvars; ++j )
2750  {
2751  SCIP_VAR* var;
2752  SCIP_Bool left;
2753  SCIP_Bool right;
2754  int duration;
2755  int lb;
2756  int ub;
2757 
2758  var = vars[j];
2759  assert(var != NULL);
2760 
2761  if( var == infervar )
2762  {
2763  if( explanation != NULL )
2764  explanation[j] = TRUE;
2765 
2766  continue;
2767  }
2768 
2769  lb = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
2770  ub = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2771 
2772  duration = durations[j];
2773  assert(duration > 0);
2774 
2775  /* in case the earliest start time is equal to hmin we have to also consider the jobs which run in that region
2776  * since we use adjusted jobs during the propagation
2777  */
2778  left = (est == hmin && lb + duration > hmin) || lb >= est;
2779 
2780  /* in case the latest completion time is equal to hmax we have to also consider the jobs which run in that region
2781  * since we use adjusted jobs during the propagation
2782  */
2783  right = (lct == hmax && ub < hmax) || ub + duration <= lct;
2784 
2785  /* store all jobs running in [est_omega; lct_omega] */
2786  if( left && right )
2787  {
2788  /* check if bound widening should be used */
2789  if( usebdwidening )
2790  {
2791  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(lct - duration)) );
2792  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(est)) );
2793  }
2794  else
2795  {
2796  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2797  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2798  }
2799 
2800  if( explanation != NULL )
2801  explanation[j] = TRUE;
2802  }
2803  }
2804 
2805  return SCIP_OKAY;
2806 }
2807 #endif
2808 
2809 /** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2810 static
2811 int computeOverlap(
2812  int begin, /**< begin of the times interval */
2813  int end, /**< end of time interval */
2814  int est, /**< earliest start time */
2815  int lst, /**< latest start time */
2816  int duration /**< duration of the job */
2817  )
2818 {
2819  int left;
2820  int right;
2821  int ect;
2822  int lct;
2823 
2824  ect = est + duration;
2825  lct = lst + duration;
2826 
2827  /* check if job runs completely within [begin,end) */
2828  if( lct <= end && est >= begin )
2829  return duration;
2830 
2831  assert(lst <= end && ect >= begin);
2832 
2833  left = ect - begin;
2834  assert(left > 0);
2835 
2836  right = end - lst;
2837  assert(right > 0);
2838 
2839  return MIN3(left, right, end - begin);
2840 }
2841 
2842 /** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2843  * reason
2844  *
2845  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2846  */
2847 static
2849  SCIP* scip, /**< SCIP data structure */
2850  int nvars, /**< number of start time variables (activities) */
2851  SCIP_VAR** vars, /**< array of start time variables */
2852  int* durations, /**< array of durations */
2853  int* demands, /**< array of demands */
2854  int capacity, /**< capacity of the cumulative condition */
2855  int begin, /**< begin of the time window */
2856  int end, /**< end of the time window */
2857  SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2858  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2859  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2860  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2861  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2862  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2863  )
2864 {
2865  int* locenergies;
2866  int* overlaps;
2867  int* idxs;
2868 
2869  SCIP_Longint requiredenergy;
2870  int v;
2871 
2872  SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2873  SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2874  SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2875 
2876  /* energy which needs be explained */
2877  requiredenergy = ((SCIP_Longint) end - begin) * capacity;
2878 
2879  SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %d)\n", begin, end, capacity, requiredenergy);
2880 
2881  /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2882  * takes
2883  */
2884  for( v = 0; v < nvars; ++v )
2885  {
2886  SCIP_VAR* var;
2887  int glbenergy;
2888  int duration;
2889  int demand;
2890  int est;
2891  int lst;
2892 
2893  var = vars[v];
2894  assert(var != NULL);
2895 
2896  locenergies[v] = 0;
2897  overlaps[v] = 0;
2898  idxs[v] = v;
2899 
2900  demand = demands[v];
2901  assert(demand > 0);
2902 
2903  duration = durations[v];
2904  assert(duration > 0);
2905 
2906  /* check if the variable equals the inference variable (the one which was propagated) */
2907  if( infervar == var )
2908  {
2909  int overlap;
2910  int right;
2911  int left;
2912 
2913  assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2914 
2915  SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2916  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2917  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2918 
2919  /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2920  * which is necessary from the inference variable
2921  */
2922  if( boundtype == SCIP_BOUNDTYPE_UPPER )
2923  {
2924  int lct;
2925 
2926  /* get the latest start time of the infer start time variable before the propagation took place */
2927  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2928 
2929  /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2930  * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2931  * scheduled w.r.t. its latest start time
2932  */
2933  assert(lst < end);
2934 
2935  /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2936  * interval (before the propagation)
2937  */
2938  right = MIN3(end - lst, end - begin, duration);
2939 
2940  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2941  assert(right > 0);
2942 
2943  lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2944  assert(begin <= lct);
2945  assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
2946 
2947  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2948  left = MIN(lct - begin + 1, end - begin);
2949  assert(left > 0);
2950 
2951  /* compute the minimum overlap; */
2952  overlap = MIN(left, right);
2953  assert(overlap > 0);
2954  assert(overlap <= end - begin);
2955  assert(overlap <= duration);
2956 
2957  if( usebdwidening )
2958  {
2959  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2960  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2961  }
2962  else
2963  {
2964  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2965  }
2966  }
2967  else
2968  {
2969  int ect;
2970 
2971  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2972 
2973  /* get the earliest completion time of the infer start time variable before the propagation took place */
2974  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2975 
2976  /* the earliest start time of the inference start time variable before the propagation needs to be larger as
2977  * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
2978  * the job is scheduled w.r.t. its earliest start time
2979  */
2980  assert(ect > begin);
2981 
2982  /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
2983  * interval (before the propagation)
2984  */
2985  left = MIN3(ect - begin, end - begin, duration);
2986 
2987  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2988  assert(left > 0);
2989 
2990  est = SCIPconvertRealToInt(scip, relaxedbd);
2991  assert(end >= est);
2992  assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
2993 
2994  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2995  right = MIN(end - est + 1, end - begin);
2996  assert(right > 0);
2997 
2998  /* compute the minimum overlap */
2999  overlap = MIN(left, right);
3000  assert(overlap > 0);
3001  assert(overlap <= end - begin);
3002  assert(overlap <= duration);
3003 
3004  if( usebdwidening )
3005  {
3006  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
3007  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
3008  }
3009  else
3010  {
3011  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
3012  }
3013  }
3014 
3015  /* subtract the amount of energy which is available due to the overlap of the inference start time */
3016  requiredenergy -= (SCIP_Longint) overlap * demand;
3017 
3018  if( explanation != NULL )
3019  explanation[v] = TRUE;
3020 
3021  continue;
3022  }
3023 
3024  /* global time points */
3025  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
3026  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
3027 
3028  glbenergy = 0;
3029 
3030  /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
3031  * time window
3032  */
3033  if( est + duration > begin && lst < end )
3034  {
3035  /* evaluated global contribution */
3036  glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
3037 
3038  /* remove the globally available energy form the required energy */
3039  requiredenergy -= glbenergy;
3040 
3041  if( explanation != NULL )
3042  explanation[v] = TRUE;
3043  }
3044 
3045  /* local time points */
3046  est = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
3047  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
3048 
3049  /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3050  * time window
3051  */
3052  if( est + duration > begin && lst < end )
3053  {
3054  overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3055 
3056  /* evaluated additionally local energy contribution */
3057  locenergies[v] = overlaps[v] * demand - glbenergy;
3058  assert(locenergies[v] >= 0);
3059  }
3060  }
3061 
3062  /* sort the variable contributions w.r.t. additional local energy contributions */
3063  SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3064 
3065  /* add local energy contributions until an overload is implied */
3066  for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3067  {
3068  SCIP_VAR* var;
3069  int duration;
3070  int overlap;
3071  int relaxlb;
3072  int relaxub;
3073  int idx;
3074 
3075  idx = idxs[v];
3076  assert(idx >= 0 && idx < nvars);
3077 
3078  var = vars[idx];
3079  assert(var != NULL);
3080  assert(var != infervar);
3081 
3082  duration = durations[idx];
3083  assert(duration > 0);
3084 
3085  overlap = overlaps[v];
3086  assert(overlap > 0);
3087 
3088  requiredenergy -= locenergies[v];
3089 
3090  if( requiredenergy < -1 )
3091  {
3092  int demand;
3093 
3094  demand = demands[idx];
3095  assert(demand > 0);
3096 
3097  overlap += (int)((requiredenergy + 1) / demand);
3098 
3099 #ifndef NDEBUG
3100  requiredenergy += locenergies[v];
3101  requiredenergy -= (SCIP_Longint) overlap * demand;
3102  assert(requiredenergy < 0);
3103 #endif
3104  }
3105  assert(overlap > 0);
3106 
3107  relaxlb = begin - duration + overlap;
3108  relaxub = end - overlap;
3109 
3110  SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3111  SCIPvarGetName(var),
3114  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var),
3115  relaxlb, relaxub, demands[idx], duration);
3116 
3117  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3118  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3119 
3120  if( explanation != NULL )
3121  explanation[idx] = TRUE;
3122  }
3123 
3124  assert(requiredenergy < 0);
3125 
3126  SCIPfreeBufferArray(scip, &idxs);
3127  SCIPfreeBufferArray(scip, &overlaps);
3128  SCIPfreeBufferArray(scip, &locenergies);
3129 
3130  return SCIP_OKAY;
3131 }
3132 
3133 /** resolve propagation w.r.t. the cumulative condition */
3134 static
3136  SCIP* scip, /**< SCIP data structure */
3137  int nvars, /**< number of start time variables (activities) */
3138  SCIP_VAR** vars, /**< array of start time variables */
3139  int* durations, /**< array of durations */
3140  int* demands, /**< array of demands */
3141  int capacity, /**< cumulative capacity */
3142  int hmin, /**< left bound of time axis to be considered (including hmin) */
3143  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3144  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3145  INFERINFO inferinfo, /**< the user information */
3146  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3147  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3148  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3149  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3150  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3151  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3152  )
3153 {
3154  switch( inferInfoGetProprule(inferinfo) )
3155  {
3156  case PROPRULE_1_CORETIMES:
3157  {
3158  int inferdemand;
3159  int inferduration;
3160  int inferpos;
3161  int inferpeak;
3162  int relaxedpeak;
3163  int provedpeak;
3164 
3165  /* get the position of the inferred variable in the vars array */
3166  inferpos = inferInfoGetData1(inferinfo);
3167  if( inferpos >= nvars || vars[inferpos] != infervar )
3168  {
3169  /* find inference variable in constraint */
3170  for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3171  {}
3172  }
3173  assert(inferpos < nvars);
3174  assert(vars[inferpos] == infervar);
3175 
3176  inferdemand = demands[inferpos];
3177  inferduration = durations[inferpos];
3178 
3179  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3180  {
3181  /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3182  * the inference variable
3183  */
3184  assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
3185 
3186  SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3187  SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
3188  SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3189 
3190  /* get the inference peak that the time point which lead to the that propagtion */
3191  inferpeak = inferInfoGetData2(inferinfo);
3192  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3193  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3194  */
3195  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3196  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) + inferduration;
3197 
3198  /* make sure that the relaxed peak is part of the effective horizon */
3199  relaxedpeak = MIN(relaxedpeak, hmax-1);
3200 
3201  /* make sure that relaxed peak is not larger than the infer peak
3202  *
3203  * This can happen in case the variable is not an active variable!
3204  */
3205  relaxedpeak = MAX(relaxedpeak, inferpeak);
3206  assert(relaxedpeak >= inferpeak);
3207  assert(relaxedpeak >= hmin);
3208  }
3209  else
3210  {
3211  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3212 
3213  SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3214  SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
3215  SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3216 
3217  /* get the time interval where the job could not be scheduled */
3218  inferpeak = inferInfoGetData2(inferinfo);
3219  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3220  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3221  */
3222  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3223  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) - 1;
3224 
3225  /* make sure that the relaxed peak is part of the effective horizon */
3226  relaxedpeak = MAX(relaxedpeak, hmin);
3227 
3228  /* make sure that relaxed peak is not larger than the infer peak
3229  *
3230  * This can happen in case the variable is not an active variable!
3231  */
3232  relaxedpeak = MIN(relaxedpeak, inferpeak);
3233  assert(relaxedpeak < hmax);
3234  }
3235 
3236  /* resolves the propagation of the core time algorithm */
3237  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3238  infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3239 
3240  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3241  {
3242  if( usebdwidening )
3243  {
3244  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3245  }
3246  else
3247  {
3248  /* old upper bound of variable itself is part of the explanation */
3249  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3250  }
3251  }
3252  else
3253  {
3254  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3255 
3256  if( usebdwidening )
3257  {
3258  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3259  }
3260  else
3261  {
3262  /* old lower bound of variable itself is part of the explanation */
3263  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3264  }
3265  }
3266 
3267  if( explanation != NULL )
3268  explanation[inferpos] = TRUE;
3269 
3270  break;
3271  }
3273  case PROPRULE_3_TTEF:
3274  {
3275  int begin;
3276  int end;
3277 
3278  begin = inferInfoGetData1(inferinfo);
3279  end = inferInfoGetData2(inferinfo);
3280  assert(begin < end);
3281 
3282  begin = MAX(begin, hmin);
3283  end = MIN(end, hmax);
3284 
3285  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3286  begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3287 
3288  break;
3289  }
3290 
3291  default:
3292  SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3293  SCIPABORT();
3294  return SCIP_INVALIDDATA; /*lint !e527*/
3295  }
3296 
3297  (*result) = SCIP_SUCCESS;
3298 
3299  return SCIP_OKAY;
3300 }
3301 
3302 /**@} */
3303 
3304 
3305 /**@name Enforcement methods
3306  *
3307  * @{
3308  */
3309 
3310 /** apply all fixings which are given by the alternative bounds */
3311 static
3313  SCIP* scip, /**< SCIP data structure */
3314  SCIP_VAR** vars, /**< array of active variables */
3315  int nvars, /**< number of active variables */
3316  int* alternativelbs, /**< alternative lower bounds */
3317  int* alternativeubs, /**< alternative lower bounds */
3318  int* downlocks, /**< number of constraints with down lock participating by the computation */
3319  int* uplocks, /**< number of constraints with up lock participating by the computation */
3320  SCIP_Bool* branched /**< pointer to store if a branching was applied */
3321  )
3322 {
3323  int v;
3324 
3325  for( v = 0; v < nvars; ++v )
3326  {
3327  SCIP_VAR* var;
3328  SCIP_Real objval;
3329 
3330  var = vars[v];
3331  assert(var != NULL);
3332 
3333  objval = SCIPvarGetObj(var);
3334 
3335  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] && !SCIPisNegative(scip, objval) )
3336  {
3337  int ub;
3338 
3339  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3340 
3341  if( alternativelbs[v] <= ub )
3342  {
3343  SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3344  (*branched) = TRUE;
3345 
3346  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3347  SCIPvarGetLbLocal(var), alternativelbs[v]);
3348 
3349  return SCIP_OKAY;
3350  }
3351  }
3352 
3353  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] && !SCIPisPositive(scip, objval) )
3354  {
3355  int lb;
3356 
3357  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3358 
3359  if( alternativeubs[v] >= lb )
3360  {
3361  SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3362  (*branched) = TRUE;
3363 
3364  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3365  alternativeubs[v], SCIPvarGetUbLocal(var));
3366 
3367  return SCIP_OKAY;
3368  }
3369  }
3370  }
3371 
3372  return SCIP_OKAY;
3373 }
3374 
3375 /** remove the capacity requirments for all job which start at the curtime */
3376 static
3378  SCIP_CONSDATA* consdata, /**< constraint data */
3379  int curtime, /**< current point in time */
3380  int* starttimes, /**< array of start times */
3381  int* startindices, /**< permutation with respect to the start times */
3382  int* freecapacity, /**< pointer to store the resulting free capacity */
3383  int* idx, /**< pointer to index in start time array */
3384  int nvars /**< number of vars in array of starttimes and startindices */
3385  )
3386 {
3387 #if defined SCIP_DEBUG && !defined NDEBUG
3388  int oldidx;
3389 
3390  assert(idx != NULL);
3391  oldidx = *idx;
3392 #else
3393  assert(idx != NULL);
3394 #endif
3395 
3396  assert(starttimes != NULL);
3397  assert(starttimes != NULL);
3398  assert(freecapacity != NULL);
3399  assert(starttimes[*idx] == curtime);
3400  assert(consdata->demands != NULL);
3401  assert(freecapacity != idx);
3402 
3403  /* subtract all capacity needed up to this point */
3404  (*freecapacity) -= consdata->demands[startindices[*idx]];
3405 
3406  while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3407  {
3408  ++(*idx);
3409  (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3410  assert(freecapacity != idx);
3411  }
3412 #ifdef SCIP_DEBUG
3413  assert(oldidx <= *idx);
3414 #endif
3415 }
3416 
3417 /** add the capacity requirments for all job which end at the curtime */
3418 static
3419 void addEndingJobDemands(
3420  SCIP_CONSDATA* consdata, /**< constraint data */
3421  int curtime, /**< current point in time */
3422  int* endtimes, /**< array of end times */
3423  int* endindices, /**< permutation with rspect to the end times */
3424  int* freecapacity, /**< pointer to store the resulting free capacity */
3425  int* idx, /**< pointer to index in end time array */
3426  int nvars /**< number of vars in array of starttimes and startindices */
3427  )
3428 {
3429 #if defined SCIP_DEBUG && !defined NDEBUG
3430  int oldidx;
3431  oldidx = *idx;
3432 #endif
3433 
3434  /* free all capacity usages of jobs the are no longer running */
3435  while( endtimes[*idx] <= curtime && *idx < nvars)
3436  {
3437  (*freecapacity) += consdata->demands[endindices[*idx]];
3438  ++(*idx);
3439  }
3440 
3441 #ifdef SCIP_DEBUG
3442  assert(oldidx <= *idx);
3443 #endif
3444 }
3445 
3446 /** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3447 static
3449  SCIP* scip, /**< SCIP data structure */
3450  SCIP_CONSDATA* consdata, /**< constraint handler data */
3451  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3452  int* timepoint /**< pointer to store the time point of the peak */
3453  )
3454 {
3455  int* starttimes; /* stores when each job is starting */
3456  int* endtimes; /* stores when each job ends */
3457  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3458  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3459 
3460  int nvars; /* number of activities for this constraint */
3461  int freecapacity; /* remaining capacity */
3462  int curtime; /* point in time which we are just checking */
3463  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3464 
3465  int hmin;
3466  int hmax;
3467 
3468  int j;
3469 
3470  assert(consdata != NULL);
3471 
3472  nvars = consdata->nvars;
3473  assert(nvars > 0);
3474 
3475  *timepoint = consdata->hmax;
3476 
3477  assert(consdata->vars != NULL);
3478 
3479  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3480  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3481  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3482  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3483 
3484  /* create event point arrays */
3485  createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3486  starttimes, endtimes, startindices, endindices);
3487 
3488  endindex = 0;
3489  freecapacity = consdata->capacity;
3490  hmin = consdata->hmin;
3491  hmax = consdata->hmax;
3492 
3493  /* check each startpoint of a job whether the capacity is kept or not */
3494  for( j = 0; j < nvars; ++j )
3495  {
3496  curtime = starttimes[j];
3497  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3498 
3499  if( curtime >= hmax )
3500  break;
3501 
3502  /* remove the capacity requirments for all job which start at the curtime */
3503  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3504 
3505  /* add the capacity requirments for all job which end at the curtime */
3506  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3507 
3508  assert(freecapacity <= consdata->capacity);
3509  assert(endindex <= nvars);
3510 
3511  /* endindex - points to the next job which will finish */
3512  /* j - points to the last job that has been released */
3513 
3514  /* if free capacity is smaller than zero, then add branching candidates */
3515  if( freecapacity < 0 && curtime >= hmin )
3516  {
3517  *timepoint = curtime;
3518  break;
3519  }
3520  } /*lint --e{850}*/
3521 
3522  /* free all buffer arrays */
3523  SCIPfreeBufferArray(scip, &endindices);
3524  SCIPfreeBufferArray(scip, &startindices);
3525  SCIPfreeBufferArray(scip, &endtimes);
3526  SCIPfreeBufferArray(scip, &starttimes);
3527 
3528  return SCIP_OKAY;
3529 }
3530 
3531 /** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3532 static
3534  SCIP* scip, /**< SCIP data structure */
3535  SCIP_CONS** conss, /**< constraints to be processed */
3536  int nconss, /**< number of constraints */
3537  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3538  int* nbranchcands /**< pointer to store the number of branching variables */
3539  )
3540 {
3541  SCIP_HASHTABLE* collectedvars;
3542  int c;
3543 
3544  assert(scip != NULL);
3545  assert(conss != NULL);
3546 
3547  /* create a hash table */
3548  SCIP_CALL( SCIPhashtableCreate(&collectedvars, SCIPblkmem(scip), SCIPgetNVars(scip),
3549  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3550 
3551  assert(scip != NULL);
3552  assert(conss != NULL);
3553 
3554  for( c = 0; c < nconss; ++c )
3555  {
3556  SCIP_CONS* cons;
3557  SCIP_CONSDATA* consdata;
3558 
3559  int curtime;
3560  int j;
3561 
3562  cons = conss[c];
3563  assert(cons != NULL);
3564 
3565  if( !SCIPconsIsActive(cons) )
3566  continue;
3567 
3568  consdata = SCIPconsGetData(cons);
3569  assert(consdata != NULL);
3570 
3571  /* get point in time when capacity is exceeded */
3572  SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3573 
3574  if( curtime < consdata->hmin || curtime >= consdata->hmax )
3575  continue;
3576 
3577  /* report all variables that are running at that point in time */
3578  for( j = 0; j < consdata->nvars; ++j )
3579  {
3580  SCIP_VAR* var;
3581  int lb;
3582  int ub;
3583 
3584  var = consdata->vars[j];
3585  assert(var != NULL);
3586 
3587  /* check if the variable was already added */
3588  if( SCIPhashtableExists(collectedvars, (void*)var) )
3589  continue;
3590 
3591  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3592  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3593 
3594  if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3595  {
3596  SCIP_Real solval;
3597  SCIP_Real score;
3598 
3599  solval = SCIPgetSolVal(scip, sol, var);
3600  score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3601 
3602  SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3603  SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3604  (*nbranchcands)++;
3605 
3606  SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3607  }
3608  }
3609  }
3610 
3611  SCIPhashtableFree(&collectedvars);
3612 
3613  SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3614 
3615  return SCIP_OKAY;
3616 }
3617 
3618 /** enforcement of an LP, pseudo, or relaxation solution */
3619 static
3621  SCIP* scip, /**< SCIP data structure */
3622  SCIP_CONS** conss, /**< constraints to be processed */
3623  int nconss, /**< number of constraints */
3624  SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
3625  SCIP_Bool branch, /**< should branching candidates be collected */
3626  SCIP_RESULT* result /**< pointer to store the result */
3627  )
3628 {
3629  if( branch )
3630  {
3631  int nbranchcands;
3632 
3633  nbranchcands = 0;
3634  SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3635 
3636  if( nbranchcands > 0 )
3637  (*result) = SCIP_INFEASIBLE;
3638  }
3639  else
3640  {
3641  SCIP_Bool violated;
3642  int c;
3643 
3644  violated = FALSE;
3645 
3646  /* first check if a constraints is violated */
3647  for( c = 0; c < nconss && !violated; ++c )
3648  {
3649  SCIP_CONS* cons;
3650 
3651  cons = conss[c];
3652  assert(cons != NULL);
3653 
3654  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3655  }
3656 
3657  if( violated )
3658  (*result) = SCIP_INFEASIBLE;
3659  }
3660 
3661  return SCIP_OKAY;
3662 }
3663 
3664 /**@} */
3665 
3666 /**@name Propagation
3667  *
3668  * @{
3669  */
3670 
3671 /** check if cumulative constraint is independently of all other constraints */
3672 static
3674  SCIP* scip, /**< SCIP data structure */
3675  SCIP_CONS* cons /**< cumulative constraint */
3676  )
3677 {
3678  SCIP_CONSDATA* consdata;
3679  SCIP_VAR** vars;
3680  SCIP_Bool* downlocks;
3681  SCIP_Bool* uplocks;
3682  int nvars;
3683  int v;
3684 
3685  consdata = SCIPconsGetData(cons);
3686  assert(consdata != NULL);
3687 
3688  nvars = consdata->nvars;
3689  vars = consdata->vars;
3690  downlocks = consdata->downlocks;
3691  uplocks = consdata->uplocks;
3692 
3693  /* check if the cumulative constraint has the only locks on the involved variables */
3694  for( v = 0; v < nvars; ++v )
3695  {
3696  SCIP_VAR* var;
3697 
3698  var = vars[v];
3699  assert(var != NULL);
3700 
3701  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
3702  || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
3703  return FALSE;
3704  }
3705 
3706  return TRUE;
3707 }
3708 
3709 /** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3710  * (dual reductions)
3711  */
3712 static
3714  SCIP* scip, /**< SCIP data structure */
3715  SCIP_CONS* cons, /**< cumulative constraint */
3716  SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3717  int* nchgbds, /**< pointer to store the number changed variable bounds */
3718  int* nfixedvars, /**< pointer to count number of fixings */
3719  int* ndelconss, /**< pointer to count number of deleted constraints */
3720  SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3721  SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3722  )
3723 {
3724  SCIP_CONSDATA* consdata;
3725  SCIP_VAR** vars;
3726  SCIP_Real* objvals;
3727  SCIP_Real* lbs;
3728  SCIP_Real* ubs;
3729  SCIP_Real timelimit;
3730  SCIP_Real memorylimit;
3731  SCIP_Bool solved;
3732  SCIP_Bool error;
3733 
3734  int ncheckconss;
3735  int nvars;
3736  int v;
3737 
3738  assert(scip != NULL);
3739  assert(!SCIPconsIsModifiable(cons));
3740  assert(SCIPgetNConss(scip) > 0);
3741 
3742  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3743  * would/could end in an implication which can lead to cutoff of the/all optimal solution
3744  */
3745  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
3746  return SCIP_OKAY;
3747 
3748  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3749  * use the locks to decide for a dual reduction using this constraint;
3750  */
3751  if( !SCIPconsIsChecked(cons) )
3752  return SCIP_OKAY;
3753 
3754  ncheckconss = SCIPgetNCheckConss(scip);
3755 
3756  /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3757  * presolved problem do nothing execpt to change the parameter settings
3758  */
3759  if( ncheckconss == 1 )
3760  {
3761  /* shrink the minimal maximum value for the conflict length */
3762  SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3763 
3764  /* use only first unique implication point */
3765  SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3766 
3767  /* do not use reconversion conflicts */
3768  SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3769 
3770  /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3771  SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3772 
3773  /* increase the number of conflicts which induce a restart */
3774  SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3775 
3776  /* weight the variable which made into a conflict */
3777  SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3778 
3779  /* do not check pseudo solution (for performance reasons) */
3780  SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3781 
3782  /* use value based history to detect a reasonable branching point */
3783  SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3784 
3785  /* turn of LP relaxation */
3786  SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3787 
3788  /* prefer the down branch in case the value based history does not suggest something */
3789  SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3790 
3791  /* accept any bound change */
3792  SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3793 
3794  /* allow for at most 10 restart, after that the value based history should be reliable */
3795  SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3796 
3797  /* set priority for depth first search to highest possible value */
3798  SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3799 
3800  return SCIP_OKAY;
3801  }
3802 
3803  consdata = SCIPconsGetData(cons);
3804  assert(consdata != NULL);
3805 
3806  /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3807  * fail on the first place
3808  */
3809  if( consdata->triedsolving )
3810  return SCIP_OKAY;
3811 
3812  /* check if constraint is independently */
3813  if( !isConsIndependently(scip, cons) )
3814  return SCIP_OKAY;
3815 
3816  /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3817  * constraint is deleted; otherwise, we want to ensure that we do not try that again
3818  */
3819  consdata->triedsolving = TRUE;
3820 
3821  SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3822  SCIPconsGetName(cons), SCIPgetNVars(scip), SCIPgetNConss(scip));
3823  SCIPdebugPrintCons(scip, cons, NULL);
3824 
3825  nvars = consdata->nvars;
3826  vars = consdata->vars;
3827 
3828  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3829  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3830  SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3831 
3832  for( v = 0; v < nvars; ++v )
3833  {
3834  SCIP_VAR* var;
3835 
3836  /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3837  * array
3838  */
3839  var = vars[v];
3840  assert(var != NULL);
3841 
3842  lbs[v] = SCIPvarGetLbLocal(var);
3843  ubs[v] = SCIPvarGetUbLocal(var);
3844 
3845  objvals[v] = SCIPvarGetObj(var);
3846  }
3847 
3848  /* check whether there is enough time and memory left */
3849  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3850  if( !SCIPisInfinity(scip, timelimit) )
3851  timelimit -= SCIPgetSolvingTime(scip);
3852  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3853 
3854  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3855  if( !SCIPisInfinity(scip, memorylimit) )
3856  {
3857  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3858  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3859  }
3860 
3861  /* solve the cumulative condition separately */
3862  SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3863  consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3864 
3865  if( !(*cutoff) && !(*unbounded) && !error )
3866  {
3867  SCIP_Bool infeasible;
3868  SCIP_Bool tightened;
3869  SCIP_Bool allfixed;
3870 
3871  allfixed = TRUE;
3872 
3873  for( v = 0; v < nvars; ++v )
3874  {
3875  /* check if variable is fixed */
3876  if( lbs[v] + 0.5 > ubs[v] )
3877  {
3878  SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3879  assert(!infeasible);
3880 
3881  if( tightened )
3882  {
3883  (*nfixedvars)++;
3884  consdata->triedsolving = FALSE;
3885  }
3886  }
3887  else
3888  {
3889  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3890  assert(!infeasible);
3891 
3892  if( tightened )
3893  {
3894  (*nchgbds)++;
3895  consdata->triedsolving = FALSE;
3896  }
3897 
3898  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3899  assert(!infeasible);
3900 
3901  if( tightened )
3902  {
3903  (*nchgbds)++;
3904  consdata->triedsolving = FALSE;
3905  }
3906 
3907  allfixed = FALSE;
3908  }
3909  }
3910 
3911  /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3912  if( allfixed )
3913  {
3914  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3915  (*ndelconss)++;
3916  }
3917  }
3918 
3919  SCIPfreeBufferArray(scip, &objvals);
3920  SCIPfreeBufferArray(scip, &ubs);
3921  SCIPfreeBufferArray(scip, &lbs);
3922 
3923  return SCIP_OKAY;
3924 }
3925 
3926 /** start conflict analysis to analysis the core insertion which is infeasible */
3927 static
3929  SCIP* scip, /**< SCIP data structure */
3930  int nvars, /**< number of start time variables (activities) */
3931  SCIP_VAR** vars, /**< array of start time variables */
3932  int* durations, /**< array of durations */
3933  int* demands, /**< array of demands */
3934  int capacity, /**< cumulative capacity */
3935  int hmin, /**< left bound of time axis to be considered (including hmin) */
3936  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3937  SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3938  int inferduration, /**< duration of the start time variable */
3939  int inferdemand, /**< demand of the start time variable */
3940  int inferpeak, /**< profile preak which causes the infeasibilty */
3941  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3942  SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3943  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3944  )
3945 {
3946  SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3947  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3948  SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3949 
3950  /* initialize conflict analysis if conflict analysis is applicable */
3952  {
3954 
3955  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3956  infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3957 
3958  SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3959 
3960  /* add both bound of the inference variable since these biuld the core which we could not inserted */
3961  if( usebdwidening )
3962  {
3963  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
3964  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
3965  }
3966  else
3967  {
3968  SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
3969  SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
3970  }
3971 
3972  *initialized = TRUE;
3973  }
3974 
3975  return SCIP_OKAY;
3976 }
3977 
3978 /** We are using the core resource profile which contains all core except the one of the start time variable which we
3979  * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
3980  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
3981  * analysis
3982  */
3983 static
3985  SCIP* scip, /**< SCIP data structure */
3986  int nvars, /**< number of start time variables (activities) */
3987  SCIP_VAR** vars, /**< array of start time variables */
3988  int* durations, /**< array of durations */
3989  int* demands, /**< array of demands */
3990  int capacity, /**< cumulative capacity */
3991  int hmin, /**< left bound of time axis to be considered (including hmin) */
3992  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3993  SCIP_CONS* cons, /**< constraint which is propagated */
3994  SCIP_PROFILE* profile, /**< resource profile */
3995  int idx, /**< position of the variable to propagate */
3996  int* nchgbds, /**< pointer to store the number of bound changes */
3997  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3998  SCIP_Bool* initialized, /**< was conflict analysis initialized */
3999  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4000  SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
4001  )
4002 {
4003  SCIP_VAR* var;
4004  int ntimepoints;
4005  int duration;
4006  int demand;
4007  int peak;
4008  int newlb;
4009  int est;
4010  int lst;
4011  int pos;
4012 
4013  var = vars[idx];
4014  assert(var != NULL);
4015 
4016  duration = durations[idx];
4017  assert(duration > 0);
4018 
4019  demand = demands[idx];
4020  assert(demand > 0);
4021 
4022  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4023  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4024  ntimepoints = SCIPprofileGetNTimepoints(profile);
4025 
4026  /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
4027  * load which we have at the earliest start time (lower bound)
4028  */
4029  (void) SCIPprofileFindLeft(profile, est, &pos);
4030 
4031  SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
4032 
4033  /* we now trying to move the earliest start time in steps of at most "duration" length */
4034  do
4035  {
4036  INFERINFO inferinfo;
4037  SCIP_Bool tightened;
4038  int ect;
4039 
4040 #ifndef NDEBUG
4041  {
4042  /* in debug mode we check that we adjust the search position correctly */
4043  int tmppos;
4044 
4045  (void)SCIPprofileFindLeft(profile, est, &tmppos);
4046  assert(pos == tmppos);
4047  }
4048 #endif
4049  ect = est + duration;
4050  peak = -1;
4051 
4052  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4053  * want a peak which is closest to the earliest completion time
4054  */
4055  do
4056  {
4057  /* check if the profile load conflicts with the demand of the start time variable */
4058  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4059  peak = pos;
4060 
4061  pos++;
4062  }
4063  while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4064 
4065  /* if we found no peak that means current the job could be scheduled at its earliest start time without
4066  * conflicting to the core resource profile
4067  */
4068  if( peak == -1 )
4069  break;
4070 
4071  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4072  * profile. That means we have to move it to the next time point in the resource profile but at most to the
4073  * earliest completion time (the remaining move will done in the next loop)
4074  */
4075  newlb = SCIPprofileGetTime(profile, peak+1);
4076  newlb = MIN(newlb, ect);
4077 
4078  /* if the earliest start time is greater than the lst we detected an infeasibilty */
4079  if( newlb > lst )
4080  {
4081  SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4082 
4083  /* use conflict analysis to analysis the core insertion which was infeasible */
4084  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4085  var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4086 
4087  if( explanation != NULL )
4088  explanation[idx] = TRUE;
4089 
4090  *infeasible = TRUE;
4091 
4092  break;
4093  }
4094 
4095  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4096  * bound change
4097  */
4098  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4099 
4100  /* perform the bound lower bound change */
4101  SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4102  assert(tightened);
4103  assert(!(*infeasible));
4104 
4105  SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4106  (*nchgbds)++;
4107 
4108  /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4110 
4111  /* adjust the earliest start time
4112  *
4113  * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4114  * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4115  * involved.
4116  */
4117  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4118  assert(est >= newlb);
4119 
4120  /* adjust the search position for the resource profile for the next step */
4121  if( est == SCIPprofileGetTime(profile, peak+1) )
4122  pos = peak + 1;
4123  else
4124  pos = peak;
4125  }
4126  while( est < lst );
4127 
4128  return SCIP_OKAY;
4129 }
4130 
4131 /** We are using the core resource profile which contains all core except the one of the start time variable which we
4132  * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4133  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4134  * analysis
4135  */
4136 static
4138  SCIP* scip, /**< SCIP data structure */
4139  SCIP_VAR* var, /**< start time variable to propagate */
4140  int duration, /**< duration of the job */
4141  int demand, /**< demand of the job */
4142  int capacity, /**< cumulative capacity */
4143  SCIP_CONS* cons, /**< constraint which is propagated */
4144  SCIP_PROFILE* profile, /**< resource profile */
4145  int idx, /**< position of the variable to propagate */
4146  int* nchgbds /**< pointer to store the number of bound changes */
4147  )
4148 {
4149  int ntimepoints;
4150  int newub;
4151  int peak;
4152  int pos;
4153  int est;
4154  int lst;
4155  int lct;
4156 
4157  assert(var != NULL);
4158  assert(duration > 0);
4159  assert(demand > 0);
4160 
4161  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4162  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4163 
4164  /* in case the start time variable is fixed do nothing */
4165  if( est == lst )
4166  return SCIP_OKAY;
4167 
4168  ntimepoints = SCIPprofileGetNTimepoints(profile);
4169 
4170  lct = lst + duration;
4171 
4172  /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4173  * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4174  * position gives us the load which we have at the latest completion time minus one
4175  */
4176  (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4177 
4178  SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4179  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
4180 
4181  if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4182  return SCIP_OKAY;
4183 
4184  /* we now trying to move the latest start time in steps of at most "duration" length */
4185  do
4186  {
4187  INFERINFO inferinfo;
4188  SCIP_Bool tightened;
4189  SCIP_Bool infeasible;
4190 
4191  peak = -1;
4192 
4193 #ifndef NDEBUG
4194  {
4195  /* in debug mode we check that we adjust the search position correctly */
4196  int tmppos;
4197 
4198  (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4199  assert(pos == tmppos);
4200  }
4201 #endif
4202 
4203  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4204  * want a peak which is closest to the latest start time
4205  */
4206  do
4207  {
4208  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4209  peak = pos;
4210 
4211  pos--;
4212  }
4213  while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4214 
4215  /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4216  * to the core resource profile
4217  */
4218  if( peak == -1 )
4219  break;
4220 
4221  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4222  * profile. That means the job has be done until that point. Hence that gives us the latest completion
4223  * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4224  * doing in the next loop)
4225  */
4226  newub = SCIPprofileGetTime(profile, peak);
4227  newub = MAX(newub, lst) - duration;
4228  assert(newub >= est);
4229 
4230  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4231  * bound change
4232  */
4233  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4234 
4235  /* perform the bound upper bound change */
4236  SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4237  assert(tightened);
4238  assert(!infeasible);
4239 
4240  SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4241  (*nchgbds)++;
4242 
4243  /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4245 
4246  /* adjust the latest start and completion time
4247  *
4248  * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4249  * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4250  * involved.
4251  */
4252  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4253  assert(lst <= newub);
4254  lct = lst + duration;
4255 
4256  /* adjust the search position for the resource profile for the next step */
4257  if( SCIPprofileGetTime(profile, peak) == lct )
4258  pos = peak - 1;
4259  else
4260  pos = peak;
4261  }
4262  while( est < lst );
4263 
4264  return SCIP_OKAY;
4265 }
4266 
4267 /** compute for the different earliest start and latest completion time the core energy of the corresponding time
4268  * points
4269  */
4270 static
4272  SCIP* scip, /**< SCIP data structure */
4273  SCIP_PROFILE* profile, /**< core profile */
4274  int nvars, /**< number of start time variables (activities) */
4275  int* ests, /**< array of sorted earliest start times */
4276  int* lcts, /**< array of sorted latest completion times */
4277  int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4278  int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4279  )
4280 {
4281  int ntimepoints;
4282  int energy;
4283  int t;
4284  int v;
4285 
4286  ntimepoints = SCIPprofileGetNTimepoints(profile);
4287  t = ntimepoints - 1;
4288  energy = 0;
4289 
4290  /* compute core energy after the earliest start time of each job */
4291  for( v = nvars-1; v >= 0; --v )
4292  {
4293  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4294  {
4295  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4296  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4297  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4298  t--;
4299  }
4300  assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4301 
4302  /* maybe ests[j] is in-between two timepoints */
4303  if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4304  {
4305  assert(t > 0);
4306  coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4307  }
4308  else
4309  coreEnergyAfterEst[v] = energy;
4310  }
4311 
4312  t = ntimepoints - 1;
4313  energy = 0;
4314 
4315  /* compute core energy after the latest completion time of each job */
4316  for( v = nvars-1; v >= 0; --v )
4317  {
4318  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4319  {
4320  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4321  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4322  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4323  t--;
4324  }
4325  assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4326 
4327  /* maybe lcts[j] is in-between two timepoints */
4328  if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4329  {
4330  assert(t > 0);
4331  coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4332  }
4333  else
4334  coreEnergyAfterLct[v] = energy;
4335  }
4336 
4337  return SCIP_OKAY;
4338 }
4339 
4340 /** collect earliest start times, latest completion time, and free energy contributions */
4341 static
4342 void collectDataTTEF(
4343  SCIP* scip, /**< SCIP data structure */
4344  int nvars, /**< number of start time variables (activities) */
4345  SCIP_VAR** vars, /**< array of start time variables */
4346  int* durations, /**< array of durations */
4347  int* demands, /**< array of demands */
4348  int hmin, /**< left bound of time axis to be considered (including hmin) */
4349  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4350  int* permests, /**< array to store the variable positions */
4351  int* ests, /**< array to store earliest start times */
4352  int* permlcts, /**< array to store the variable positions */
4353  int* lcts, /**< array to store latest completion times */
4354  int* ects, /**< array to store earliest completion times of the flexible part of the job */
4355  int* lsts, /**< array to store latest start times of the flexible part of the job */
4356  int* flexenergies /**< array to store the flexible energies of each job */
4357  )
4358 {
4359  int v;
4360 
4361  for( v = 0; v < nvars; ++ v)
4362  {
4363  int duration;
4364  int leftadjust;
4365  int rightadjust;
4366  int core;
4367  int est;
4368  int lct;
4369  int ect;
4370  int lst;
4371 
4372  duration = durations[v];
4373  assert(duration > 0);
4374 
4375  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4376  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
4377  ect = est + duration;
4378  lct = lst + duration;
4379 
4380  ests[v] = est;
4381  lcts[v] = lct;
4382  permests[v] = v;
4383  permlcts[v] = v;
4384 
4385  /* compute core time window which lies within the effective horizon */
4386  core = (int) computeCoreWithInterval(hmin, hmax, ect, lst);
4387 
4388  /* compute the number of time steps the job could run before the effective horizon */
4389  leftadjust = MAX(0, hmin - est);
4390 
4391  /* compute the number of time steps the job could run after the effective horizon */
4392  rightadjust = MAX(0, lct - hmax);
4393 
4394  /* compute for each job the energy which is flexible; meaning not part of the core */
4395  flexenergies[v] = duration - leftadjust - rightadjust - core;
4396  flexenergies[v] = MAX(0, flexenergies[v]);
4397  flexenergies[v] *= demands[v];
4398  assert(flexenergies[v] >= 0);
4399 
4400  /* the earliest completion time of the flexible energy */
4401  ects[v] = MIN(ect, lst);
4402 
4403  /* the latest start time of the flexible energy */
4404  lsts[v] = MAX(ect, lst);
4405  }
4406 }
4407 
4408 /** try to tighten the lower bound of the given variable */
4409 static
4411  SCIP* scip, /**< SCIP data structure */
4412  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4413  int nvars, /**< number of start time variables (activities) */
4414  SCIP_VAR** vars, /**< array of start time variables */
4415  int* durations, /**< array of durations */
4416  int* demands, /**< array of demands */
4417  int capacity, /**< cumulative capacity */
4418  int hmin, /**< left bound of time axis to be considered (including hmin) */
4419  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4420  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4421  int duration, /**< duration of the job */
4422  int demand, /**< demand of the job */
4423  int est, /**< earliest start time of the job */
4424  int ect, /**< earliest completion time of the flexible part of the job */
4425  int lct, /**< latest completion time of the job */
4426  int begin, /**< begin of the time window under investigation */
4427  int end, /**< end of the time window under investigation */
4428  SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4429  int* bestlb, /**< pointer to strope the best lower bound change */
4430  int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4431  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4432  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4433  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4434  )
4435 {
4436  int newlb;
4437 
4438  assert(begin >= hmin);
4439  assert(end <= hmax);
4440 
4441  /* check if the time-table edge-finding should infer bounds */
4442  if( !conshdlrdata->ttefinfer )
4443  return SCIP_OKAY;
4444 
4445  /* if the job can be processed completely before or after the time window, nothing can be tightened */
4446  if( est >= end || ect <= begin )
4447  return SCIP_OKAY;
4448 
4449  /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4450  * skip since the overload check will do the job
4451  */
4452  if( est >= begin && ect <= end )
4453  return SCIP_OKAY;
4454 
4455  /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4456  * earliest start time
4457  */
4458  if( energy >= demand * ((SCIP_Longint) MAX(begin, est) - MIN(end, ect)) )
4459  return SCIP_OKAY;
4460 
4461  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4462  * present; therefore, we need to add the core;
4463  *
4464  * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4465  * compute the earliest completion time of the (whole) job
4466  */
4467  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4468 
4469  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4470  *
4471  * @note we can round down the compute duration w.r.t. the available energy
4472  */
4473  newlb = end - (int) (energy / demand);
4474 
4475  /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4476  * bound (latest start time); meaning it is not possible to schedule the job
4477  */
4478  if( newlb > lct - duration )
4479  {
4480  /* initialize conflict analysis if conflict analysis is applicable */
4482  {
4483  SCIP_Real relaxedbd;
4484 
4485  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4486 
4487  /* it is enough to overshoot the upper bound of the variable by one */
4488  relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4489 
4490  /* initialize conflict analysis */
4492 
4493  /* added to upper bound (which was overcut be new lower bound) of the variable */
4494  SCIP_CALL( SCIPaddConflictUb(scip, var, NULL) );
4495 
4496  /* analyze the infeasible */
4497  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4498  begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4499 
4500  (*initialized) = TRUE;
4501  }
4502 
4503  (*cutoff) = TRUE;
4504  }
4505  else if( newlb > (*bestlb) )
4506  {
4507  INFERINFO inferinfo;
4508 
4509  assert(newlb > begin);
4510 
4511  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4512 
4513  /* construct inference information */
4514  (*inferinfos) = inferInfoToInt(inferinfo);
4515  (*bestlb) = newlb;
4516  }
4517 
4518  return SCIP_OKAY;
4519 }
4520 
4521 /** try to tighten the upper bound of the given variable */
4522 static
4524  SCIP* scip, /**< SCIP data structure */
4525  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4526  int nvars, /**< number of start time variables (activities) */
4527  SCIP_VAR** vars, /**< array of start time variables */
4528  int* durations, /**< array of durations */
4529  int* demands, /**< array of demands */
4530  int capacity, /**< cumulative capacity */
4531  int hmin, /**< left bound of time axis to be considered (including hmin) */
4532  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4533  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4534  int duration, /**< duration of the job */
4535  int demand, /**< demand of the job */
4536  int est, /**< earliest start time of the job */
4537  int lst, /**< latest start time of the flexible part of the job */
4538  int lct, /**< latest completion time of the job */
4539  int begin, /**< begin of the time window under investigation */
4540  int end, /**< end of the time window under investigation */
4541  SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4542  int* bestub, /**< pointer to strope the best upper bound change */
4543  int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4544  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4545  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4546  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4547  )
4548 {
4549  int newub;
4550 
4551  assert(begin >= hmin);
4552  assert(end <= hmax);
4553  assert(est < begin);
4554 
4555  /* check if the time-table edge-finding should infer bounds */
4556  if( !conshdlrdata->ttefinfer )
4557  return SCIP_OKAY;
4558 
4559  /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4560  if( lst >= end || lct <= begin )
4561  return SCIP_OKAY;
4562 
4563  /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4564  * skip since the overload check will do the job
4565  */
4566  if( lst >= begin && lct <= end )
4567  return SCIP_OKAY;
4568 
4569  /* check if the available energy in the time window is to small to handle the flexible part of the job */
4570  if( energy >= demand * ((SCIP_Longint) MIN(end, lct) - MAX(begin, lst)) )
4571  return SCIP_OKAY;
4572 
4573  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4574  * present; therefore, we need to add the core;
4575  *
4576  * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4577  * latest start of the (whole) job
4578  */
4579  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4580  assert(energy >= 0);
4581 
4582  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4583  *
4584  * @note we can round down the compute duration w.r.t. the available energy
4585  */
4586  assert(demand > 0);
4587  newub = begin - duration + (int) (energy / demand);
4588 
4589  /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4590  * bound (earliest start time); meaning it is not possible to schedule the job
4591  */
4592  if( newub < est )
4593  {
4594  /* initialize conflict analysis if conflict analysis is applicable */
4596  {
4597  SCIP_Real relaxedbd;
4598 
4599  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4600 
4601  /* it is enough to undershoot the lower bound of the variable by one */
4602  relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4603 
4604  /* initialize conflict analysis */
4606 
4607  /* added to lower bound (which was undercut be new upper bound) of the variable */
4608  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
4609 
4610  /* analyze the infeasible */
4611  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4612  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4613 
4614  (*initialized) = TRUE;
4615  }
4616 
4617  (*cutoff) = TRUE;
4618  }
4619  else if( newub < (*bestub) )
4620  {
4621  INFERINFO inferinfo;
4622 
4623  assert(newub < begin);
4624 
4625  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4626 
4627  /* construct inference information */
4628  (*inferinfos) = inferInfoToInt(inferinfo);
4629  (*bestub) = newub;
4630  }
4631 
4632  return SCIP_OKAY;
4633 }
4634 
4635 /** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4636 static
4638  SCIP* scip, /**< SCIP data structure */
4639  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4640  int nvars, /**< number of start time variables (activities) */
4641  SCIP_VAR** vars, /**< array of start time variables */
4642  int* durations, /**< array of durations */
4643  int* demands, /**< array of demands */
4644  int capacity, /**< cumulative capacity */
4645  int hmin, /**< left bound of time axis to be considered (including hmin) */
4646  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4647  int* newlbs, /**< array to buffer new lower bounds */
4648  int* newubs, /**< array to buffer new upper bounds */
4649  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4650  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4651  int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4652  int* flexenergies, /**< array of flexible energies in the same order as the variables */
4653  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4654  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4655  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4656  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4657  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4658  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4659  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4660  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4661  )
4662 {
4663  int coreEnergyAfterEnd;
4664  SCIP_Longint maxavailable;
4665  SCIP_Longint minavailable;
4666  SCIP_Longint totalenergy;
4667  int nests;
4668  int est;
4669  int lct;
4670  int start;
4671  int end;
4672  int v;
4673 
4674  est = INT_MAX;
4675  lct = INT_MIN;
4676 
4677  /* compute earliest start and latest completion time of all jobs */
4678  for( v = 0; v < nvars; ++v )
4679  {
4680  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4681  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4682 
4683  est = MIN(est, start);
4684  lct = MAX(lct, end);
4685  }
4686 
4687  /* adjust the effective time horizon */
4688  hmin = MAX(hmin, est);
4689  hmax = MIN(hmax, lct);
4690 
4691  end = hmax + 1;
4692  coreEnergyAfterEnd = -1;
4693 
4694  maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
4695  minavailable = maxavailable;
4696  totalenergy = computeTotalEnergy(durations, demands, nvars);
4697 
4698  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4699  if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4700  return SCIP_OKAY;
4701 
4702  nests = nvars;
4703 
4704  /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4705  * times define the end of the time interval under investigation
4706  */
4707  for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4708  {
4709  int flexenergy;
4710  int minbegin;
4711  int lbenergy;
4712  int lbcand;
4713  int i;
4714 
4715  lct = lcts[v];
4716 
4717  /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4718  * infinity capacity is available; hence we skip that
4719  */
4720  if( lct > hmax )
4721  continue;
4722 
4723  /* if the latest completion time is smaller then hmin we have to stop */
4724  if( lct <= hmin )
4725  {
4726  assert(v == 0 || lcts[v-1] <= lcts[v]);
4727  break;
4728  }
4729 
4730  /* if the latest completion time equals to previous end time, we can continue since this particular interval
4731  * induced by end was just analyzed
4732  */
4733  if( lct == end )
4734  continue;
4735 
4736  assert(lct < end);
4737 
4738  /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4739  * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4740  * free energy; if so it means that in the next iterate the free-energy cannot be negative
4741  */
4742  if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4743  {
4744  SCIP_Longint freeenergy;
4745 
4746  assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4747  assert(coreEnergyAfterEnd >= 0);
4748 
4749  /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4750  freeenergy = capacity * ((SCIP_Longint) end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4751 
4752  if( freeenergy <= minavailable )
4753  {
4754  SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%d>, free energy <%d>)\n", lct, minavailable, freeenergy);
4755  continue;
4756  }
4757  }
4758 
4759  SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4760 
4761  end = lct;
4762  coreEnergyAfterEnd = coreEnergyAfterLct[v];
4763 
4764  flexenergy = 0;
4765  minavailable = maxavailable;
4766  minbegin = hmax;
4767  lbcand = -1;
4768  lbenergy = 0;
4769 
4770  /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4771  * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4772  * wider
4773  */
4774  for( i = nests-1; i >= 0; --i )
4775  {
4776  SCIP_VAR* var;
4777  SCIP_Longint freeenergy;
4778  int duration;
4779  int demand;
4780  int begin;
4781  int idx;
4782  int lst;
4783 
4784  idx = perm[i];
4785  assert(idx >= 0);
4786  assert(idx < nvars);
4787  assert(!(*cutoff));
4788 
4789  /* the earliest start time of the job */
4790  est = ests[i];
4791 
4792  /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4793  * latest completion times (which define end) are scant in non-increasing order
4794  */
4795  if( end <= est )
4796  {
4797  nests--;
4798  continue;
4799  }
4800 
4801  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4802  * current ending time
4803  */
4804  if( ((SCIP_Longint) end - est) * capacity >= totalenergy )
4805  break;
4806 
4807  var = vars[idx];
4808  assert(var != NULL);
4809 
4810  duration = durations[idx];
4811  assert(duration > 0);
4812 
4813  demand = demands[idx];
4814  assert(demand > 0);
4815 
4816  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4817 
4818  /* the latest start time of the free part of the job */
4819  lst = lsts[idx];
4820 
4821  /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4822  * investigation; hence the overload check will do the the job
4823  */
4824  assert(est <= minbegin);
4825  if( minavailable < maxavailable && est < minbegin )
4826  {
4827  assert(!(*cutoff));
4828 
4829  /* try to tighten the upper bound */
4830  SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4831  var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4832  initialized, explanation, cutoff) );
4833 
4834  if( *cutoff )
4835  break;
4836  }
4837 
4838  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4839  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4840 
4841  begin = est;
4842  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4843 
4844  /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4845  * free energy
4846  */
4847  if( begin < hmin )
4848  break;
4849 
4850  /* compute the contribution to the flexible energy */
4851  if( lct <= end )
4852  {
4853  /* if the jobs has to finish before the end, all the energy has to be scheduled */
4854  assert(lst >= begin);
4855  assert(flexenergies[idx] >= 0);
4856  flexenergy += flexenergies[idx];
4857  }
4858  else
4859  {
4860  /* the job partly overlaps with the end */
4861  int candenergy;
4862  int energy;
4863 
4864  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4865  * w.r.t. latest start time
4866  *
4867  * @note we need to be aware of the effective horizon
4868  */
4869  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4870  assert(end - lst < duration);
4871  assert(energy >= 0);
4872 
4873  /* adjust the flexible energy of the time interval */
4874  flexenergy += energy;
4875 
4876  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4877  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4878  assert(candenergy >= 0);
4879 
4880  /* check if we found a better candidate */
4881  if( candenergy > lbenergy )
4882  {
4883  lbenergy = candenergy;
4884  lbcand = idx;
4885  }
4886  }
4887 
4888  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4889  assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4890 
4891  /* compute the energy which is not used yet */
4892  freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4893 
4894  /* check overload */
4895  if( freeenergy < 0 )
4896  {
4897  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4898 
4899  /* initialize conflict analysis if conflict analysis is applicable */
4901  {
4902  /* analyze infeasibilty */
4904 
4905  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4906  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
4907  conshdlrdata->usebdwidening, explanation) );
4908 
4909  (*initialized) = TRUE;
4910  }
4911 
4912  (*cutoff) = TRUE;
4913 
4914  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4915  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
4916 
4917  break;
4918  }
4919 
4920  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4921  if( lbenergy > 0 && freeenergy < lbenergy )
4922  {
4923  SCIP_Longint energy;
4924  int newlb;
4925  int ect;
4926 
4927  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4928  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4929 
4930  /* remove the energy of our job from the ... */
4931  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) end - lsts[lbcand])) * demands[lbcand];
4932 
4933  newlb = end - (int)(energy / demands[lbcand]);
4934 
4935  if( newlb > lst )
4936  {
4937  /* initialize conflict analysis if conflict analysis is applicable */
4939  {
4940  SCIP_Real relaxedbd;
4941 
4942  /* analyze infeasibilty */
4944 
4945  relaxedbd = lst + 1.0;
4946 
4947  /* added to upper bound (which was overcut be new lower bound) of the variable */
4948  SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4949 
4950  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4951  begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
4952  conshdlrdata->usebdwidening, explanation) );
4953 
4954  (*initialized) = TRUE;
4955  }
4956 
4957  (*cutoff) = TRUE;
4958  break;
4959  }
4960  else if( newlb > newlbs[lbcand] )
4961  {
4962  INFERINFO inferinfo;
4963 
4964  /* construct inference information */
4965  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4966 
4967  /* buffer upper bound change */
4968  lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
4969  newlbs[lbcand] = newlb;
4970  }
4971  }
4972 
4973  /* check if the current interval has a smaller free energy */
4974  if( minavailable > freeenergy )
4975  {
4976  minavailable = freeenergy;
4977  minbegin = begin;
4978  }
4979  assert(minavailable >= 0);
4980  }
4981  }
4982 
4983  return SCIP_OKAY;
4984 }
4985 
4986 /** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
4987 static
4989  SCIP* scip, /**< SCIP data structure */
4990  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4991  int nvars, /**< number of start time variables (activities) */
4992  SCIP_VAR** vars, /**< array of start time variables */
4993  int* durations, /**< array of durations */
4994  int* demands, /**< array of demands */
4995  int capacity, /**< cumulative capacity */
4996  int hmin, /**< left bound of time axis to be considered (including hmin) */
4997  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4998  int* newlbs, /**< array to buffer new lower bounds */
4999  int* newubs, /**< array to buffer new upper bounds */
5000  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
5001  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
5002  int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
5003  int* flexenergies, /**< array of flexible energies in the same order as the variables */
5004  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
5005  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
5006  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
5007  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
5008  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
5009  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5010  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5011  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5012  )
5013 {
5014  int coreEnergyAfterStart;
5015  SCIP_Longint maxavailable;
5016  SCIP_Longint minavailable;
5017  SCIP_Longint totalenergy;
5018  int nlcts;
5019  int begin;
5020  int minest;
5021  int maxlct;
5022  int start;
5023  int end;
5024  int v;
5025 
5026  if( *cutoff )
5027  return SCIP_OKAY;
5028 
5029  begin = hmin - 1;
5030 
5031  minest = INT_MAX;
5032  maxlct = INT_MIN;
5033 
5034  /* compute earliest start and latest completion time of all jobs */
5035  for( v = 0; v < nvars; ++v )
5036  {
5037  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5038  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
5039 
5040  minest = MIN(minest, start);
5041  maxlct = MAX(maxlct, end);
5042  }
5043 
5044  /* adjust the effective time horizon */
5045  hmin = MAX(hmin, minest);
5046  hmax = MIN(hmax, maxlct);
5047 
5048  maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
5049  totalenergy = computeTotalEnergy(durations, demands, nvars);
5050 
5051  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5052  if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5053  return SCIP_OKAY;
5054 
5055  nlcts = 0;
5056 
5057  /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5058  * define the start of the time interval under investigation
5059  */
5060  for( v = 0; v < nvars; ++v )
5061  {
5062  int flexenergy;
5063  int minend;
5064  int ubenergy;
5065  int ubcand;
5066  int est;
5067  int i;
5068 
5069  est = ests[v];
5070 
5071  /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5072  * infinity capacity is available; hence we skip that
5073  */
5074  if( est < hmin )
5075  continue;
5076 
5077  /* if the earliest start time is larger or equal then hmax we have to stop */
5078  if( est >= hmax )
5079  break;
5080 
5081  /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5082  * induced by start was just analyzed
5083  */
5084  if( est == begin )
5085  continue;
5086 
5087  assert(est > begin);
5088 
5089  SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5090 
5091  begin = est;
5092  coreEnergyAfterStart = coreEnergyAfterEst[v];
5093 
5094  flexenergy = 0;
5095  minavailable = maxavailable;
5096  minend = hmin;
5097  ubcand = -1;
5098  ubenergy = 0;
5099 
5100  /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5101  * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5102  */
5103  for( i = nlcts; i < nvars; ++i )
5104  {
5105  SCIP_VAR* var;
5106  SCIP_Longint freeenergy;
5107  int duration;
5108  int demand;
5109  int idx;
5110  int lct;
5111  int ect;
5112 
5113  idx = perm[i];
5114  assert(idx >= 0);
5115  assert(idx < nvars);
5116  assert(!(*cutoff));
5117 
5118  /* the earliest start time of the job */
5119  lct = lcts[i];
5120 
5121  /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5122  * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5123  */
5124  if( lct <= begin )
5125  {
5126  nlcts++;
5127  continue;
5128  }
5129 
5130  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5131  * start with current beginning time
5132  */
5133  if( ((SCIP_Longint) lct - begin) * capacity >= totalenergy )
5134  break;
5135 
5136  var = vars[idx];
5137  assert(var != NULL);
5138 
5139  duration = durations[idx];
5140  assert(duration > 0);
5141 
5142  demand = demands[idx];
5143  assert(demand > 0);
5144 
5145  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5146 
5147  /* the earliest completion time of the flexible part of the job */
5148  ect = ects[idx];
5149 
5150  /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5151  * investigation; hence the overload check will do the the job
5152  */
5153  assert(lct >= minend);
5154  if( minavailable < maxavailable && lct > minend )
5155  {
5156  assert(!(*cutoff));
5157 
5158  /* try to tighten the upper bound */
5159  SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5160  var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5161  initialized, explanation, cutoff) );
5162 
5163  if( *cutoff )
5164  return SCIP_OKAY;
5165  }
5166 
5167  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5168  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5169 
5170  end = lct;
5171  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5172 
5173  /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5174  * free energy
5175  */
5176  if( end > hmax )
5177  break;
5178 
5179  /* compute the contribution to the flexible energy */
5180  if( est >= begin )
5181  {
5182  /* if the jobs has to finish before the end, all the energy has to be scheduled */
5183  assert(ect <= end);
5184  assert(flexenergies[idx] >= 0);
5185  flexenergy += flexenergies[idx];
5186  }
5187  else
5188  {
5189  /* the job partly overlaps with the end */
5190  int candenergy;
5191  int energy;
5192 
5193  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5194  * w.r.t. latest start time
5195  *
5196  * @note we need to be aware of the effective horizon
5197  */
5198  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5199  assert(ect - begin < duration);
5200  assert(energy >= 0);
5201 
5202  /* adjust the flexible energy of the time interval */
5203  flexenergy += energy;
5204 
5205  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5206  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5207  assert(candenergy >= 0);
5208 
5209  /* check if we found a better candidate */
5210  if( candenergy > ubenergy )
5211  {
5212  ubenergy = candenergy;
5213  ubcand = idx;
5214  }
5215  }
5216 
5217  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5218  assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5219 
5220  /* compute the energy which is not used yet */
5221  freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5222 
5223  /* check overload */
5224  if( freeenergy < 0 )
5225  {
5226  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5227 
5228  /* initialize conflict analysis if conflict analysis is applicable */
5230  {
5231  /* analyze infeasibilty */
5233 
5234  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5235  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
5236  conshdlrdata->usebdwidening, explanation) );
5237 
5238  (*initialized) = TRUE;
5239  }
5240 
5241  (*cutoff) = TRUE;
5242 
5243  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5244  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5245 
5246  return SCIP_OKAY;
5247  }
5248 
5249  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5250  if( ubenergy > 0 && freeenergy < ubenergy )
5251  {
5252  SCIP_Longint energy;
5253  int newub;
5254  int lst;
5255 
5256  duration = durations[ubcand];
5257  assert(duration > 0);
5258 
5259  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5260  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5261 
5262  /* remove the energy of our job from the ... */
5263  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) ects[ubcand] - begin)) * demands[ubcand];
5264 
5265  newub = begin - duration + (int)(energy / demands[ubcand]);
5266 
5267  if( newub < ect - duration )
5268  {
5269  /* initialize conflict analysis if conflict analysis is applicable */
5271  {
5272  SCIP_Real relaxedbd;
5273  /* analyze infeasibilty */
5275 
5276  relaxedbd = ect - duration - 1.0;
5277 
5278  /* added to lower bound (which was undercut be new upper bound) of the variable */
5279  SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5280 
5281  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5282  begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5283  conshdlrdata->usebdwidening, explanation) );
5284 
5285  (*initialized) = TRUE;
5286  }
5287 
5288  (*cutoff) = TRUE;
5289  return SCIP_OKAY;
5290  }
5291  else if( newub < newubs[ubcand] )
5292  {
5293  INFERINFO inferinfo;
5294 
5295  /* construct inference information */
5296  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5297 
5298  /* buffer upper bound change */
5299  ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5300  newubs[ubcand] = newub;
5301  }
5302  }
5303 
5304  /* check if the current interval has a smaller free energy */
5305  if( minavailable > freeenergy )
5306  {
5307  minavailable = freeenergy;
5308  minend = end;
5309  }
5310  assert(minavailable >= 0);
5311  }
5312  }
5313 
5314  return SCIP_OKAY;
5315 }
5316 
5317 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5318  * edge-finding
5319  *
5320  * @note The algorithm is based on the following two papers:
5321  * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5322  * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5323  * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5324  * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5325  * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5326  */
5327 static
5329  SCIP* scip, /**< SCIP data structure */
5330  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5331  SCIP_PROFILE* profile, /**< current core profile */
5332  int nvars, /**< number of start time variables (activities) */
5333  SCIP_VAR** vars, /**< array of start time variables */
5334  int* durations, /**< array of durations */
5335  int* demands, /**< array of demands */
5336  int capacity, /**< cumulative capacity */
5337  int hmin, /**< left bound of time axis to be considered (including hmin) */
5338  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5339  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5340  int* nchgbds, /**< pointer to store the number of bound changes */
5341  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5342  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5343  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5344  )
5345 {
5346  int* coreEnergyAfterEst;
5347  int* coreEnergyAfterLct;
5348  int* flexenergies;
5349  int* permests;
5350  int* permlcts;
5351  int* lcts;
5352  int* ests;
5353  int* ects;
5354  int* lsts;
5355 
5356  int* newlbs;
5357  int* newubs;
5358  int* lbinferinfos;
5359  int* ubinferinfos;
5360 
5361  int v;
5362 
5363  /* check if a cutoff was already detected */
5364  if( (*cutoff) )
5365  return SCIP_OKAY;
5366 
5367  /* check if at least the basic overload checking should be perfomed */
5368  if( !conshdlrdata->ttefcheck )
5369  return SCIP_OKAY;
5370 
5371  SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5372 
5373  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5374  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5375  SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5376  SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5377  SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5378  SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5379  SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5380  SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5381  SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5382 
5383  SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5384  SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5385  SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5386  SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5387 
5388  /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5389  for( v = 0; v < nvars; ++v )
5390  {
5391  newlbs[v] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5392  newubs[v] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5393  lbinferinfos[v] = 0;
5394  ubinferinfos[v] = 0;
5395  }
5396 
5397  /* collect earliest start times, latest completion time, and free energy contributions */
5398  collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5399 
5400  /* sort the earliest start times and latest completion in non-decreasing order */
5401  SCIPsortIntInt(ests, permests, nvars);
5402  SCIPsortIntInt(lcts, permlcts, nvars);
5403 
5404  /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5405  * points
5406  */
5407  SCIP_CALL( computeCoreEngeryAfter(scip, profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct) );
5408 
5409  /* propagate the upper bounds and "opportunistically" the lower bounds */
5410  SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5411  newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5412  permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5413 
5414  /* propagate the lower bounds and "opportunistically" the upper bounds */
5415  SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5416  newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5417  permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5418 
5419  /* apply the buffer bound changes */
5420  for( v = 0; v < nvars && !(*cutoff); ++v )
5421  {
5422  SCIP_Bool infeasible;
5423  SCIP_Bool tightened;
5424 
5425  SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v], TRUE, &infeasible, &tightened) );
5426 
5427  /* since we change first the lower bound of the variable an infeasibilty should be detected */
5428  assert(!infeasible);
5429 
5430  if( tightened )
5431  {
5432  (*nchgbds)++;
5433 
5434  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5436  }
5437 
5438  SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v], TRUE, &infeasible, &tightened) );
5439 
5440  /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5441  * bound update can be infeasible
5442  */
5443  if( infeasible )
5444  {
5446  {
5447  INFERINFO inferinfo;
5448  SCIP_VAR* var;
5449  int begin;
5450  int end;
5451 
5452  var = vars[v];
5453  assert(var != NULL);
5454 
5455  /* initialize conflict analysis */
5457 
5458  /* convert int to inference information */
5459  inferinfo = intToInferInfo(ubinferinfos[v]);
5460 
5461  /* collect time window from inference information */
5462  begin = inferInfoGetData1(inferinfo);
5463  end = inferInfoGetData2(inferinfo);
5464  assert(begin < end);
5465 
5466  /* added to lower bound (which was undercut be new upper bound) of the variable */
5467  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
5468 
5469  /* analysis the upper bound change */
5470  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5471  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5472  conshdlrdata->usebdwidening, explanation) );
5473 
5474  (*initialized) = TRUE;
5475  }
5476 
5477  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5478  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5479 
5480  (*cutoff) = TRUE;
5481  break;
5482  }
5483 
5484  if( tightened )
5485  {
5486  (*nchgbds)++;
5487 
5488  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5490  }
5491  }
5492 
5493  SCIPfreeBufferArray(scip, &ubinferinfos);
5494  SCIPfreeBufferArray(scip, &lbinferinfos);
5495  SCIPfreeBufferArray(scip, &newubs);
5496  SCIPfreeBufferArray(scip, &newlbs);
5497 
5498  /* free buffer arrays */
5499  SCIPfreeBufferArray(scip, &lsts);
5500  SCIPfreeBufferArray(scip, &ects);
5501  SCIPfreeBufferArray(scip, &ests);
5502  SCIPfreeBufferArray(scip, &lcts);
5503  SCIPfreeBufferArray(scip, &permests);
5504  SCIPfreeBufferArray(scip, &permlcts);
5505  SCIPfreeBufferArray(scip, &flexenergies);
5506  SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5507  SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5508 
5509  return SCIP_OKAY;
5510 }
5511 
5512 /** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5513  * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5514  * time table propagator
5515  */
5516 static
5518  SCIP* scip, /**< SCIP data structure */
5519  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5520  SCIP_PROFILE* profile, /**< core profile */
5521  int nvars, /**< number of start time variables (activities) */
5522  SCIP_VAR** vars, /**< array of start time variables */
5523  int* durations, /**< array of durations */
5524  int* demands, /**< array of demands */
5525  int capacity, /**< cumulative capacity */
5526  int hmin, /**< left bound of time axis to be considered (including hmin) */
5527  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5528  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5529  int* nchgbds, /**< pointer to store the number of bound changes */
5530  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5531  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5532  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5533  )
5534 {
5535  SCIP_Bool infeasible;
5536  int v;
5537 
5538  assert(scip != NULL);
5539  assert(nvars > 0);
5540  assert(cons != NULL);
5541  assert(cutoff != NULL);
5542 
5543  /* check if already a cutoff was detected */
5544  if( (*cutoff) )
5545  return SCIP_OKAY;
5546 
5547  /* check if the time tabling should infer bounds */
5548  if( !conshdlrdata->ttinfer )
5549  return SCIP_OKAY;
5550 
5551  assert(*initialized == FALSE);
5552 
5553  SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5554  SCIPconsGetName(cons), hmin, hmax, capacity);
5555 
5556  infeasible = FALSE;
5557 
5558  /* if core profile is empty; nothing to do */
5559  if( SCIPprofileGetNTimepoints(profile) <= 1 )
5560  return SCIP_OKAY;
5561 
5562  /* start checking each job whether the bounds can be improved */
5563  for( v = 0; v < nvars; ++v )
5564  {
5565  SCIP_VAR* var;
5566  int demand;
5567  int duration;
5568  int begin;
5569  int end;
5570  int est;
5571  int lst;
5572 
5573  var = vars[v];
5574  assert(var != NULL);
5575 
5576  duration = durations[v];
5577  assert(duration > 0);
5578 
5579  /* collect earliest and latest start time */
5580  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5581  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5582 
5583  /* check if the start time variables is already fixed; in that case we can ignore the job */
5584  if( est == lst )
5585  continue;
5586 
5587  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5588  if( lst + duration <= hmin || est >= hmax )
5589  continue;
5590 
5591  /* compute core interval w.r.t. effective time horizon */
5592  begin = MAX(hmin, lst);
5593  end = MIN(hmax, est + duration);
5594 
5595  demand = demands[v];
5596  assert(demand > 0);
5597 
5598  /* if the job has a core, remove it first */
5599  if( begin < end )
5600  {
5601  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5602  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5603 
5604  SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5605  }
5606 
5607  /* first try to update the earliest start time */
5608  SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5609  profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5610 
5611  if( *cutoff )
5612  break;
5613 
5614  /* second try to update the latest start time */
5615  SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5616  profile, v, nchgbds) );
5617 
5618  if( *cutoff )
5619  break;
5620 
5621  /* collect the potentially updated earliest and latest start time */
5622  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5623  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5624 
5625  /* compute core interval w.r.t. effective time horizon */
5626  begin = MAX(hmin, lst);
5627  end = MIN(hmax, est + duration);
5628 
5629  /* after updating the bound we might have a new core */
5630  if( begin < end )
5631  {
5632  int pos;
5633 
5634  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5635  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5636 
5637  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5638 
5639  if( infeasible )
5640  {
5641  /* use conflict analysis to analysis the core insertion which was infeasible */
5642  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5643  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5644 
5645  if( explanation != NULL )
5646  explanation[v] = TRUE;
5647 
5648  (*cutoff) = TRUE;
5649 
5650  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5651  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
5652 
5653  break;
5654  }
5655  }
5656  }
5657 
5658  return SCIP_OKAY;
5659 }
5660 
5661 
5662 /** node data structure for the binary tree used for edgefinding (with overload checking) */
5663 struct SCIP_NodeData
5664 {
5665  SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5666  SCIP_Real key; /**< key which is to insert the corresponding search node */
5667  int est; /**< earliest start time if the node data belongs to a leaf */
5668  int lct; /**< latest completion time if the node data belongs to a leaf */
5669  int demand; /**< demand of the job if the node data belongs to a leaf */
5670  int duration; /**< duration of the job if the node data belongs to a leaf */
5671  int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5672  int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5673  SCIP_Longint enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5674  int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5675  int energylambda;
5676  SCIP_Longint enveloplambda;
5677  int idx; /**< index of the start time variable in the (global) variable array */
5678  SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5679 };
5680 typedef struct SCIP_NodeData SCIP_NODEDATA;
5682 /** creates a node data structure */
5683 static
5685  SCIP* scip, /**< SCIP data structure */
5686  SCIP_NODEDATA** nodedata /**< pointer to store the create node data */
5687  )
5688 {
5689  SCIP_CALL( SCIPallocBuffer(scip, nodedata) );
5690  (*nodedata)->var = NULL;
5691  (*nodedata)->key = SCIP_INVALID;
5692  (*nodedata)->est = INT_MIN;
5693  (*nodedata)->lct = INT_MAX;
5694  (*nodedata)->duration = 0;
5695  (*nodedata)->demand = 0;
5696  (*nodedata)->enveloptheta = -1;
5697  (*nodedata)->energytheta = 0;
5698  (*nodedata)->enveloplambda = -1;
5699  (*nodedata)->energylambda = -1;
5700  (*nodedata)->idx = -1;
5701  (*nodedata)->intheta = TRUE;
5702 
5703  return SCIP_OKAY;
5704 }
5705 
5706 /** frees a node data structure */
5707 static
5708 void freeNodedata(
5709  SCIP* scip, /**< SCIP data structure */
5710  SCIP_NODEDATA** nodedata /**< pointer to store node data which should be freed */
5711  )
5712 {
5713  if( *nodedata != NULL )
5714  {
5715  SCIPfreeBuffer(scip, nodedata);
5716  }
5717 }
5718 
5719 /** update node data structure strating form the given node along the path to the root node */
5720 static
5722  SCIP* scip, /**< SCIP data structure */
5723  SCIP_BTNODE* node /**< search node which inserted */
5724  )
5725 {
5726  SCIP_BTNODE* left;
5727  SCIP_BTNODE* right;
5728  SCIP_NODEDATA* nodedata;
5729  SCIP_NODEDATA* leftdata;
5730  SCIP_NODEDATA* rightdata;
5731 
5732  SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5733 
5734  if( SCIPbtnodeIsLeaf(node) )
5735  node = SCIPbtnodeGetParent(node);
5736 
5737  while( node != NULL )
5738  {
5739  /* get node data */
5740  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5741  assert(nodedata != NULL);
5742 
5743  /* collect node data from left node */
5744  left = SCIPbtnodeGetLeftchild(node);
5745  assert(left != NULL);
5746  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5747  assert(leftdata != NULL);
5748 
5749  /* collect node data from right node */
5750  right = SCIPbtnodeGetRightchild(node);
5751  assert(right != NULL);
5752  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5753  assert(rightdata != NULL);
5754 
5755  /* update envelop and energy */
5756  if( leftdata->enveloptheta >= 0 )
5757  {
5758  assert(rightdata->energytheta != -1);
5759  nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5760  }
5761  else
5762  nodedata->enveloptheta = rightdata->enveloptheta;
5763 
5764  assert(leftdata->energytheta != -1);
5765  assert(rightdata->energytheta != -1);
5766  nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5767 
5768  if( leftdata->enveloplambda >= 0 )
5769  {
5770  assert(rightdata->energytheta != -1);
5771  nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5772  }
5773  else
5774  nodedata->enveloplambda = rightdata->enveloplambda;
5775 
5776  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5777  nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5778 
5779  SCIPdebugMsg(scip, "node <%p> lambda envelop %d\n", (void*)node, nodedata->enveloplambda);
5780 
5781  if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5782  {
5783  assert(rightdata->energytheta != -1);
5784  assert(leftdata->energytheta != -1);
5785  nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5786  }
5787  else if( rightdata->energylambda >= 0 )
5788  {
5789  assert(leftdata->energytheta != -1);
5790  nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5791  }
5792  else if( leftdata->energylambda >= 0 )
5793  {
5794  assert(rightdata->energytheta != -1);
5795  nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5796  }
5797  else
5798  nodedata->energylambda = -1;
5799 
5800  /* go to parent */
5801  node = SCIPbtnodeGetParent(node);
5802  }
5803 
5804  SCIPdebugMsg(scip, "updating done\n");
5805 
5806  return SCIP_OKAY;
5807 }
5808 
5809 /** updates the key of the first parent on the trace which comes from left */
5810 static
5811 void updateKeyOnTrace(
5812  SCIP_BTNODE* node, /**< node to start the trace */
5813  SCIP_Real key /**< update search key */
5814  )
5815 {
5816  assert(node != NULL);
5817 
5818  while( !SCIPbtnodeIsRoot(node) )
5819  {
5820  SCIP_BTNODE* parent;
5821 
5822  parent = SCIPbtnodeGetParent(node);
5823  assert(parent != NULL);
5824 
5825  if( SCIPbtnodeIsLeftchild(node) )
5826  {
5827  SCIP_NODEDATA* nodedata;
5828 
5829  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(parent);
5830  assert(nodedata != NULL);
5831 
5832  nodedata->key = key;
5833  return;
5834  }
5835 
5836  node = parent;
5837  }
5838 }
5839 
5840 
5841 /** deletes the given node and updates all envelops */
5842 static
5844  SCIP* scip, /**< SCIP data structure */
5845  SCIP_BT* tree, /**< binary tree */
5846  SCIP_BTNODE* node /**< node to be deleted */
5847  )
5848 {
5849  SCIP_BTNODE* parent;
5850  SCIP_BTNODE* grandparent;
5851  SCIP_BTNODE* sibling;
5852 
5853  assert(scip != NULL);
5854  assert(tree != NULL);
5855  assert(node != NULL);
5856 
5857  assert(SCIPbtnodeIsLeaf(node));
5858  assert(!SCIPbtnodeIsRoot(node));
5859 
5860  SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5861 
5862  parent = SCIPbtnodeGetParent(node);
5863  assert(parent != NULL);
5864  if( SCIPbtnodeIsLeftchild(node) )
5865  {
5866  sibling = SCIPbtnodeGetRightchild(parent);
5867  SCIPbtnodeSetRightchild(parent, NULL);
5868  }
5869  else
5870  {
5871  sibling = SCIPbtnodeGetLeftchild(parent);
5872  SCIPbtnodeSetLeftchild(parent, NULL);
5873  }
5874  assert(sibling != NULL);
5875 
5876  grandparent = SCIPbtnodeGetParent(parent);
5877 
5878  if( grandparent != NULL )
5879  {
5880  /* reset parent of sibling */
5881  SCIPbtnodeSetParent(sibling, grandparent);
5882 
5883  /* reset child of grandparent to sibling */
5884  if( SCIPbtnodeIsLeftchild(parent) )
5885  {
5886  SCIPbtnodeSetLeftchild(grandparent, sibling);
5887  }
5888  else
5889  {
5890  SCIP_NODEDATA* nodedata;
5891 
5892  assert(SCIPbtnodeIsRightchild(parent));
5893  SCIPbtnodeSetRightchild(grandparent, sibling);
5894 
5895  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(sibling);
5896 
5897  updateKeyOnTrace(grandparent, nodedata->key);
5898  }
5899 
5900  SCIP_CALL( updateEnvelop(scip, grandparent) );
5901  }
5902  else
5903  {
5904  SCIPbtnodeSetParent(sibling, NULL);
5905 
5906  SCIPbtSetRoot(tree, sibling);
5907  }
5908 
5909  SCIPbtnodeFree(tree, &parent);
5910 
5911  return SCIP_OKAY;
5912 }
5913 
5914 /** moves a node form the theta set into the lambda set and updates the envelops */
5915 static
5917  SCIP* scip, /**< SCIP data structure */
5918  SCIP_BT* tree, /**< binary tree */
5919  SCIP_BTNODE* node /**< node to move into the lambda set */
5920  )
5921 {
5922  SCIP_NODEDATA* nodedata;
5923 
5924  assert(scip != NULL);
5925  assert(tree != NULL);
5926  assert(node != NULL);
5927 
5928  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5929  assert(nodedata != NULL);
5930  assert(nodedata->intheta);
5931 
5932  /* move the contributions form the theta set into the lambda set */
5933  assert(nodedata->enveloptheta != -1);
5934  assert(nodedata->energytheta != -1);
5935  assert(nodedata->enveloplambda == -1);
5936  assert(nodedata->energylambda == -1);
5937  nodedata->enveloplambda = nodedata->enveloptheta;
5938  nodedata->energylambda = nodedata->energytheta;
5939 
5940  nodedata->enveloptheta = -1;
5941  nodedata->energytheta = 0;
5942  nodedata->intheta = FALSE;
5943 
5944  /* update the energy and envelop values on trace */
5945  SCIP_CALL( updateEnvelop(scip, node) );
5946 
5947  return SCIP_OKAY;
5948 }
5949 
5950 /** inserts a node into the theta set and update the envelops */
5951 static
5953  SCIP* scip, /**< SCIP data structure */
5954  SCIP_BT* tree, /**< binary tree */
5955  SCIP_BTNODE* node, /**< node to insert */
5956  SCIP_NODEDATA** nodedatas, /**< array of node data */
5957  int* nnodedatas /**< pointer to number of node data */
5958  )
5959 {
5960  /* if the tree is empty the node will be the root node */
5961  if( SCIPbtIsEmpty(tree) )
5962  {
5963  SCIPbtSetRoot(tree, node);
5964  }
5965  else
5966  {
5967  SCIP_NODEDATA* newnodedata;
5968  SCIP_NODEDATA* leafdata;
5969  SCIP_NODEDATA* nodedata;
5970  SCIP_BTNODE* leaf;
5971  SCIP_BTNODE* newnode;
5972  SCIP_BTNODE* parent;
5973 
5974  leaf = SCIPbtGetRoot(tree);
5975  assert(leaf != NULL);
5976 
5977  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5978  assert(leafdata != NULL);
5979 
5980  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5981  assert(nodedata != NULL);
5982  assert(nodedata->intheta);
5983 
5984  /* find the position to insert the node */
5985  while( !SCIPbtnodeIsLeaf(leaf) )
5986  {
5987  if( nodedata->key < leafdata->key )
5988  leaf = SCIPbtnodeGetLeftchild(leaf);
5989  else
5990  leaf = SCIPbtnodeGetRightchild(leaf);
5991 
5992  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5993  assert(leafdata != NULL);
5994  }
5995 
5996  assert(leaf != NULL);
5997  assert(leaf != node);
5998 
5999  /* create node data */
6000  SCIP_CALL( createNodedata(scip, &newnodedata) );
6001 
6002  /* create a new node */
6003  SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
6004  assert(newnode != NULL);
6005 
6006  /* store node data to be able to delete them latter */
6007  nodedatas[*nnodedatas] = newnodedata;
6008  (*nnodedatas)++;
6009 
6010  parent = SCIPbtnodeGetParent(leaf);
6011 
6012  if( parent != NULL )
6013  {
6014  SCIPbtnodeSetParent(newnode, parent);
6015 
6016  /* check if the node is the left child */
6017  if( SCIPbtnodeGetLeftchild(parent) == leaf )
6018  {
6019  SCIPbtnodeSetLeftchild(parent, newnode);
6020  }
6021  else
6022  {
6023  SCIPbtnodeSetRightchild(parent, newnode);
6024  }
6025  }
6026  else
6027  SCIPbtSetRoot(tree, newnode);
6028 
6029  if( nodedata->key < leafdata->key )
6030  {
6031  /* node is on the left */
6032  SCIPbtnodeSetLeftchild(newnode, node);
6033  SCIPbtnodeSetRightchild(newnode, leaf);
6034  newnodedata->key = nodedata->key;
6035  }
6036  else
6037  {
6038  /* leaf is on the left */
6039  SCIPbtnodeSetLeftchild(newnode, leaf);
6040  SCIPbtnodeSetRightchild(newnode, node);
6041  newnodedata->key = leafdata->key;
6042  }
6043 
6044  SCIPbtnodeSetParent(leaf, newnode);
6045  SCIPbtnodeSetParent(node, newnode);
6046  }
6047 
6048  /* update envelop */
6049  SCIP_CALL( updateEnvelop(scip, node) );
6050 
6051  return SCIP_OKAY;
6052 }
6053 
6054 /** returns the leaf responsible for the lambda energy */
6055 static
6057  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6058  )
6059 {
6060  SCIP_BTNODE* left;
6061  SCIP_BTNODE* right;
6062  SCIP_NODEDATA* nodedata;
6063  SCIP_NODEDATA* leftdata;
6064  SCIP_NODEDATA* rightdata;
6065 
6066  assert(node != NULL);
6067 
6068  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6069  assert(nodedata != NULL);
6070 
6071  /* check if the node is the (responsible) leaf */
6072  if( SCIPbtnodeIsLeaf(node) )
6073  {
6074  assert(!nodedata->intheta);
6075  return node;
6076  }
6077 
6078  left = SCIPbtnodeGetLeftchild(node);
6079  assert(left != NULL);
6080 
6081  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6082  assert(leftdata != NULL);
6083 
6084  right = SCIPbtnodeGetRightchild(node);
6085  assert(right != NULL);
6086 
6087  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6088  assert(rightdata != NULL);
6089 
6090  assert(nodedata->energylambda != -1);
6091  assert(rightdata->energytheta != -1);
6092 
6093  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6095 
6096  assert(leftdata->energytheta != -1);
6097  assert(rightdata->energylambda != -1);
6098  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6099 
6101 }
6102 
6103 /** returns the leaf responsible for the lambda envelop */
6104 static
6106  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6107  )
6108 {
6109  SCIP_BTNODE* left;
6110  SCIP_BTNODE* right;
6111  SCIP_NODEDATA* nodedata;
6112  SCIP_NODEDATA* leftdata;
6113  SCIP_NODEDATA* rightdata;
6114 
6115  assert(node != NULL);
6116 
6117  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6118  assert(nodedata != NULL);
6119 
6120  /* check if the node is the (responsible) leaf */
6121  if( SCIPbtnodeIsLeaf(node) )
6122  {
6123  assert(!nodedata->intheta);
6124  return node;
6125  }
6126 
6127  left = SCIPbtnodeGetLeftchild(node);
6128  assert(left != NULL);
6129 
6130  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6131  assert(leftdata != NULL);
6132 
6133  right = SCIPbtnodeGetRightchild(node);
6134  assert(right != NULL);
6135 
6136  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6137  assert(rightdata != NULL);
6138 
6139  assert(nodedata->enveloplambda != -1);
6140  assert(rightdata->energytheta != -1);
6141 
6142  /* check if the left or right child is the one defining the envelop for the lambda set */
6143  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6145  else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6146  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6148 
6149  assert(rightdata->enveloplambda != -1);
6150  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6151 
6153 }
6154 
6155 
6156 /** reports all elements from set theta to generate a conflicting set */
6157 static
6158 void collectThetaSubtree(
6159  SCIP_BTNODE* node, /**< node within a theta subtree */
6160  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6161  int* nelements, /**< pointer to store the number of elements in omegaset */
6162  int* est, /**< pointer to store the earliest start time of the omega set */
6163  int* lct, /**< pointer to store the latest start time of the omega set */
6164  int* energy /**< pointer to store the energy of the omega set */
6165  )
6166 {
6167  SCIP_NODEDATA* nodedata;
6168 
6169  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6170  assert(nodedata != NULL);
6171 
6172  if( !SCIPbtnodeIsLeaf(node) )
6173  {
6174  collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6175  collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6176  }
6177  else if( nodedata->intheta )
6178  {
6179  assert(nodedata->var != NULL);
6180  SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6181 
6182  omegaset[*nelements] = node;
6183  (*est) = MIN(*est, nodedata->est);
6184  (*lct) = MAX(*lct, nodedata->lct);
6185  (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6186  (*nelements)++;
6187  }
6188 }
6189 
6190 
6191 /** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6192 static
6193 void traceThetaEnvelop(
6194  SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6195  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6196  int* nelements, /**< pointer to store the number of elements in omegaset */
6197  int* est, /**< pointer to store the earliest start time of the omega set */
6198  int* lct, /**< pointer to store the latest start time of the omega set */
6199  int* energy /**< pointer to store the energy of the omega set */
6200  )
6201 {
6202  assert(node != NULL);
6203 
6204  if( SCIPbtnodeIsLeaf(node) )
6205  {
6206  collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6207  }
6208  else
6209  {
6210  SCIP_BTNODE* left;
6211  SCIP_BTNODE* right;
6212  SCIP_NODEDATA* nodedata;
6213  SCIP_NODEDATA* leftdata;
6214  SCIP_NODEDATA* rightdata;
6215 
6216  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6217  assert(nodedata != NULL);
6218 
6219  left = SCIPbtnodeGetLeftchild(node);
6220  assert(left != NULL);
6221 
6222  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6223  assert(leftdata != NULL);
6224 
6225  right = SCIPbtnodeGetRightchild(node);
6226  assert(right != NULL);
6227 
6228  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6229  assert(rightdata != NULL);
6230 
6231  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6232  assert(nodedata != NULL);
6233 
6234  assert(nodedata->enveloptheta != -1);
6235  assert(rightdata->energytheta != -1);
6236 
6237  if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6238  {
6239  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6240  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6241  }
6242  else
6243  {
6244  assert(rightdata->enveloptheta != -1);
6245  assert(nodedata->enveloptheta == rightdata->enveloptheta);
6246  traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6247  }
6248  }
6249 }
6250 
6251 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6252 static
6253 void traceLambdaEnergy(
6254  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6255  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6256  int* nelements, /**< pointer to store the number of elements in omega set */
6257  int* est, /**< pointer to store the earliest start time of the omega set */
6258  int* lct, /**< pointer to store the latest start time of the omega set */
6259  int* energy /**< pointer to store the energy of the omega set */
6260  )
6261 {
6262  SCIP_BTNODE* left;
6263  SCIP_BTNODE* right;
6264  SCIP_NODEDATA* nodedata;
6265  SCIP_NODEDATA* leftdata;
6266  SCIP_NODEDATA* rightdata;
6267 
6268  assert(node != NULL);
6269 
6270  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6271  assert(nodedata != NULL);
6272 
6273  /* check if the node is a leaf */
6274  if( SCIPbtnodeIsLeaf(node) )
6275  return;
6276 
6277  left = SCIPbtnodeGetLeftchild(node);
6278  assert(left != NULL);
6279 
6280  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6281  assert(leftdata != NULL);
6282 
6283  right = SCIPbtnodeGetRightchild(node);
6284  assert(right != NULL);
6285 
6286  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6287  assert(rightdata != NULL);
6288 
6289  assert(nodedata->energylambda != -1);
6290  assert(rightdata->energytheta != -1);
6291 
6292  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6293  {
6294  traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6295  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6296  }
6297  else
6298  {
6299  assert(leftdata->energytheta != -1);
6300  assert(rightdata->energylambda != -1);
6301  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6302 
6303  collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6304  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6305  }
6306 }
6307 
6308 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6309 static
6310 void traceLambdaEnvelop(
6311  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6312  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6313  int* nelements, /**< pointer to store the number of elements in omega set */
6314  int* est, /**< pointer to store the earliest start time of the omega set */
6315  int* lct, /**< pointer to store the latest start time of the omega set */
6316  int* energy /**< pointer to store the energy of the omega set */
6317  )
6318 {
6319  SCIP_BTNODE* left;
6320  SCIP_BTNODE* right;
6321  SCIP_NODEDATA* nodedata;
6322  SCIP_NODEDATA* leftdata;
6323  SCIP_NODEDATA* rightdata;
6324 
6325  assert(node != NULL);
6326 
6327  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6328  assert(nodedata != NULL);
6329 
6330  /* check if the node is a leaf */
6331  if( SCIPbtnodeIsLeaf(node) )
6332  {
6333  assert(!nodedata->intheta);
6334  return;
6335  }
6336 
6337  left = SCIPbtnodeGetLeftchild(node);
6338  assert(left != NULL);
6339 
6340  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6341  assert(leftdata != NULL);
6342 
6343  right = SCIPbtnodeGetRightchild(node);
6344  assert(right != NULL);
6345 
6346  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6347  assert(rightdata != NULL);
6348 
6349  assert(nodedata->enveloplambda != -1);
6350  assert(rightdata->energytheta != -1);
6351 
6352  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6353  {
6354  traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6355  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6356  }
6357  else
6358  {
6359  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6360  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6361  {
6362  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6363  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6364  }
6365  else
6366  {
6367  assert(rightdata->enveloplambda != -1);
6368  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6369  traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6370  }
6371  }
6372 }
6373 
6374 /** compute the energy contribution by job which corresponds to the given leaf */
6375 static
6377  SCIP_BTNODE* node /**< leaf */
6378  )
6379 {
6380  SCIP_NODEDATA* nodedata;
6381  int duration;
6382 
6383  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6384  assert(nodedata != NULL);
6385  assert(nodedata->var != NULL);
6386 
6387  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6388  assert(duration > 0);
6389 
6390  SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6392  SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6393 
6394  /* return energy which is contributed by the start time variable */
6395  return nodedata->demand * duration;
6396 }
6397 
6398 /** comparison method for two node data w.r.t. the earliest start time */
6399 static
6400 SCIP_DECL_SORTPTRCOMP(compNodeEst)
6402  int est1;
6403  int est2;
6404 
6405  est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6406  est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6407 
6408  return (est1 - est2);
6409 }
6410 
6411 /** comparison method for two node data w.r.t. the latest completion time */
6412 static
6413 SCIP_DECL_SORTPTRCOMP(compNodedataLct)
6415  int lct1;
6416  int lct2;
6417 
6418  lct1 = ((SCIP_NODEDATA*)elem1)->lct;
6419  lct2 = ((SCIP_NODEDATA*)elem2)->lct;
6420 
6421  return (lct1 - lct2);
6422 }
6423 
6424 
6425 /** an overload was detected; initialized conflict analysis, add an initial reason
6426  *
6427  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6428  */
6429 static
6431  SCIP* scip, /**< SCIP data structure */
6432  SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6433  int capacity, /**< cumulative capacity */
6434  int nleaves, /**< number of responsible leaves */
6435  int est, /**< earliest start time of the ...... */
6436  int lct, /**< latest completly time of the .... */
6437  int reportedenergy, /**< energy which already reported */
6438  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6439  int shift, /**< shift applied to all jobs before adding them to the tree */
6440  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6441  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6442  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6443  )
6444 {
6445  SCIP_Longint energy;
6446  int j;
6447 
6448  /* do nothing if conflict analysis is not applicable */
6450  return SCIP_OKAY;
6451 
6452  SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6453 
6454  /* compute energy of initial time window */
6455  energy = ((SCIP_Longint) lct - est) * capacity;
6456 
6457  /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6458  SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6459 
6460  /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6461  * thereby, compute the time window of interest
6462  */
6463  for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6464  {
6465  SCIP_NODEDATA* nodedata;
6466 
6467  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6468  assert(nodedata != NULL);
6469 
6470  reportedenergy += computeEnergyContribution(leaves[j]);
6471 
6472  /* adjust energy if the earliest start time decrease */
6473  if( nodedata->est < est )
6474  {
6475  est = nodedata->est;
6476  energy = ((SCIP_Longint) lct - est) * capacity;
6477  }
6478  }
6479  assert(reportedenergy > energy);
6480 
6481  SCIPdebugMsg(scip, "time window [%d,%d) available energy %d, required energy %d\n", est, lct, energy, reportedenergy);
6482 
6483  /* initialize conflict analysis */
6485 
6486  /* flip earliest start time and latest completion time */
6487  if( !propest )
6488  {
6489  SCIPswapInts(&est, &lct);
6490 
6491  /* shift earliest start time and latest completion time */
6492  lct = shift - lct;
6493  est = shift - est;
6494  }
6495  else
6496  {
6497  /* shift earliest start time and latest completion time */
6498  lct = lct + shift;
6499  est = est + shift;
6500  }
6501 
6502  nleaves = j;
6503 
6504  /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6505  * overloaded
6506  */
6507  for( j = nleaves-1; j >= 0; --j )
6508  {
6509  SCIP_NODEDATA* nodedata;
6510 
6511  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6512  assert(nodedata != NULL);
6513  assert(nodedata->var != NULL);
6514 
6515  /* check if bound widening should be used */
6516  if( usebdwidening )
6517  {
6518  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6519  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6520  }
6521  else
6522  {
6523  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6524  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6525  }
6526 
6527  if( explanation != NULL )
6528  explanation[nodedata->idx] = TRUE;
6529  }
6530 
6531  (*initialized) = TRUE;
6532 
6533  return SCIP_OKAY;
6534 }
6535 
6536 /** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6537  * responsible interval bounds in *est_omega and *lct_omega
6538  */
6539 static
6540 int computeEstOmegaset(
6541  SCIP* scip, /**< SCIP data structure */
6542  int duration, /**< duration of the job to move */
6543  int demand, /**< demand of the job to move */
6544  int capacity, /**< cumulative capacity */
6545  int est, /**< earliest start time of the omega set */
6546  int lct, /**< latest start time of the omega set */
6547  int energy /**< energy of the omega set */
6548  )
6549 {
6550  int newest;
6551 
6552  newest = 0;
6553 
6554  assert(scip != NULL);
6555 
6556  if( energy > ((SCIP_Longint) capacity - demand) * ((SCIP_Longint) lct - est) )
6557  {
6558  if( energy + (SCIP_Longint) demand * duration > capacity * ((SCIP_Longint) lct - est) )
6559  {
6560  newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6561  newest += est;
6562  }
6563  }
6564 
6565  return newest;
6566 }
6567 
6568 /** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6569  *
6570  * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6571  * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6572  */
6573 static
6575  SCIP* scip, /**< SCIP data structure */
6576  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6577  SCIP_CONS* cons, /**< constraint which is propagated */
6578  SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6579  SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6580  int capacity, /**< cumulative capacity */
6581  int ncands, /**< number of candidates */
6582  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6583  int shift, /**< shift applied to all jobs before adding them to the tree */
6584  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6585  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6586  int* nchgbds, /**< pointer to store the number of bound changes */
6587  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6588  )
6589 {
6590  SCIP_NODEDATA* rootdata;
6591  int j;
6592 
6593  assert(!SCIPbtIsEmpty(tree));
6594 
6595  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6596  assert(rootdata != NULL);
6597 
6598  /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6599  for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6600  {
6601  SCIP_NODEDATA* nodedata;
6602 
6603  if( SCIPbtnodeIsRoot(leaves[j]) )
6604  break;
6605 
6606  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6607  assert(nodedata->est != -1);
6608 
6609  /* check if the root lambda envelop exeeds the available capacity */
6610  while( !(*cutoff) && rootdata->enveloplambda > (SCIP_Longint) capacity * nodedata->lct )
6611  {
6612  SCIP_BTNODE** omegaset;
6613  SCIP_BTNODE* leaf;
6614  SCIP_NODEDATA* leafdata;
6615  int nelements;
6616  int energy;
6617  int newest;
6618  int est;
6619  int lct;
6620 
6621  assert(!(*cutoff));
6622 
6623  /* find responsible leaf for the lambda envelope */
6625  assert(leaf != NULL);
6626  assert(SCIPbtnodeIsLeaf(leaf));
6627 
6628  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6629  assert(leafdata != NULL);
6630  assert(!leafdata->intheta);
6631  assert(leafdata->duration > 0);
6632  assert(leafdata->est >= 0);
6633 
6634  /* check if the job has to be removed since its latest completion is to large */
6635  if( leafdata->est + leafdata->duration >= nodedata->lct )
6636  {
6637  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6638 
6639  /* the root might changed therefore we need to collect the new root node data */
6640  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6641  assert(rootdata != NULL);
6642 
6643  continue;
6644  }
6645 
6646  /* compute omega set */
6647  SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6648 
6649  nelements = 0;
6650  est = INT_MAX;
6651  lct = INT_MIN;
6652  energy = 0;
6653 
6654  /* collect the omega set from theta set */
6655  traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6656  assert(nelements > 0);
6657  assert(nelements < ncands);
6658 
6659  newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6660 
6661  /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6662  if( newest > lct )
6663  {
6664  SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6665 
6666  /* analyze over load */
6667  SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6668  conshdlrdata->usebdwidening, initialized, explanation) );
6669  (*cutoff) = TRUE;
6670 
6671  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6672  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6673  }
6674  else if( newest > 0 )
6675  {
6676  SCIP_Bool infeasible;
6677  SCIP_Bool tightened;
6678  INFERINFO inferinfo;
6679 
6680  if( propest )
6681  {
6682  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6683  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6684 
6685  SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6686  SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6687 
6688  SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6689  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6690 
6691  /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6693  }
6694  else
6695  {
6696  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6697  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6698 
6699  SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6700  SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6701 
6702  SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6703  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6704 
6705  /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6707  }
6708 
6709  /* adjust the earliest start time */
6710  if( tightened )
6711  {
6712  leafdata->est = newest;
6713  (*nchgbds)++;
6714  }
6715 
6716  if( infeasible )
6717  {
6718  /* initialize conflict analysis if conflict analysis is applicable */
6720  {
6721  int i;
6722 
6723  SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6724 
6726 
6727  /* add lower and upper bound of variable which leads to the infeasibilty */
6728  SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6729  SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6730 
6731  if( explanation != NULL )
6732  explanation[leafdata->idx] = TRUE;
6733 
6734  /* add lower and upper bound of variable which lead to the infeasibilty */
6735  for( i = 0; i < nelements; ++i )
6736  {
6737  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6738  assert(nodedata != NULL);
6739 
6740  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6741  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6742 
6743  if( explanation != NULL )
6744  explanation[nodedata->idx] = TRUE;
6745  }
6746 
6747  (*initialized) = TRUE;
6748  }
6749 
6750  (*cutoff) = TRUE;
6751 
6752  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6753  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6754  }
6755  }
6756 
6757  /* free omegaset array */
6758  SCIPfreeBufferArray(scip, &omegaset);
6759 
6760  /* delete responsible leaf from lambda */
6761  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6762 
6763  /* the root might changed therefore we need to collect the new root node data */
6764  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6765  assert(rootdata != NULL);
6766  }
6767 
6768  /* move current job j from the theta set into the lambda set */
6769  SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6770  }
6771 
6772  return SCIP_OKAY;
6773 }
6774 
6775 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6776  *
6777  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6778  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6779  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6780  */
6781 static
6783  SCIP* scip, /**< SCIP data structure */
6784  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6785  int nvars, /**< number of start time variables (activities) */
6786  SCIP_VAR** vars, /**< array of start time variables */
6787  int* durations, /**< array of durations */
6788  int* demands, /**< array of demands */
6789  int capacity, /**< cumulative capacity */
6790  int hmin, /**< left bound of time axis to be considered (including hmin) */
6791  int hmax, /**< right bound of time axis to be considered (not including hmax) */
6792  SCIP_CONS* cons, /**< constraint which is propagated */
6793  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6794  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6795  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6796  int* nchgbds, /**< pointer to store the number of bound changes */
6797  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6798  )
6799 {
6800  SCIP_NODEDATA** nodedatas;
6801  SCIP_BTNODE** leaves;
6802  SCIP_BT* tree;
6803 
6804  int totalenergy;
6805  int nnodedatas;
6806  int ninsertcands;
6807  int ncands;
6808 
6809  int shift;
6810  int j;
6811 
6812  assert(scip != NULL);
6813  assert(cons != NULL);
6814  assert(initialized != NULL);
6815  assert(cutoff != NULL);
6816  assert(*cutoff == FALSE);
6817 
6818  SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6819 
6820  SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6821  SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6822 
6823  ncands = 0;
6824  totalenergy = 0;
6825 
6826  SCIP_CALL( SCIPbtCreate(&tree, SCIPblkmem(scip)) );
6827 
6828  /* compute the shift which we apply to compute .... latest completion time of all jobs */
6829  if( propest )
6830  shift = 0;
6831  else
6832  {
6833  shift = 0;
6834 
6835  /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6836  * earliest start time propagation to handle the latest completion times
6837  */
6838  for( j = 0; j < nvars; ++j )
6839  {
6840  int lct;
6841 
6842  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6843  shift = MAX(shift, lct);
6844  }
6845  }
6846 
6847  /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6848  * horizon
6849  */
6850  for( j = 0; j < nvars; ++j )
6851  {
6852  SCIP_NODEDATA* nodedata;
6853  SCIP_VAR* var;
6854  int duration;
6855  int leftadjust;
6856  int rightadjust;
6857  int energy;
6858  int est;
6859  int lct;
6860 
6861  var = vars[j];
6862  assert(var != NULL);
6863 
6864  duration = durations[j];
6865  assert(duration > 0);
6866 
6867  leftadjust = 0;
6868  rightadjust = 0;
6869 
6870  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
6871  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6872 
6873  /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6874  * effective horizon [hmin,hmax)
6875  */
6876  if( conshdlrdata->useadjustedjobs )
6877  {
6878  if( est < hmin )
6879  {
6880  leftadjust = (hmin - est);
6881  est = hmin;
6882  }
6883  if( lct > hmax )
6884  {
6885  rightadjust = (lct - hmax);
6886  lct = hmax;
6887  }
6888 
6889  /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6890  * with the effective time horizon
6891  */
6892  if( duration - leftadjust - rightadjust <= 0 )
6893  continue;
6894  }
6895  else if( est < hmin || lct > hmax )
6896  continue;
6897 
6898  energy = demands[j] * (duration - leftadjust - rightadjust);
6899  assert(energy > 0);
6900 
6901  totalenergy += energy;
6902 
6903  /* flip earliest start time and latest completion time */
6904  if( !propest )
6905  {
6906  SCIPswapInts(&est, &lct);
6907 
6908  /* shift earliest start time and latest completion time */
6909  lct = shift - lct;
6910  est = shift - est;
6911  }
6912  else
6913  {
6914  /* shift earliest start time and latest completion time */
6915  lct = lct - shift;
6916  est = est - shift;
6917  }
6918  assert(est < lct);
6919  assert(est >= 0);
6920  assert(lct >= 0);
6921 
6922  /* create search node data */
6923  SCIP_CALL( createNodedata(scip, &nodedata) );
6924 
6925  /* initialize search node data */
6926  /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6927  nodedata->key = est + j / (2.0 * nvars);
6928  nodedata->var = var;
6929  nodedata->est = est;
6930  nodedata->lct = lct;
6931  nodedata->demand = demands[j];
6932  nodedata->duration = duration;
6933  nodedata->leftadjust = leftadjust;
6934  nodedata->rightadjust = rightadjust;
6935 
6936  /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6937  * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6938  * particular time interval [a,b] against the time interval [0,b].
6939  */
6940  nodedata->enveloptheta = (SCIP_Longint) capacity * est + energy;
6941  nodedata->energytheta = energy;
6942  nodedata->enveloplambda = -1;
6943  nodedata->energylambda = -1;
6944 
6945  nodedata->idx = j;
6946  nodedata->intheta = TRUE;
6947 
6948  nodedatas[ncands] = nodedata;
6949  ncands++;
6950  }
6951 
6952  nnodedatas = ncands;
6953 
6954  /* sort (non-decreasing) the jobs w.r.t. latest completion times */
6955  SCIPsortPtr((void**)nodedatas, compNodedataLct, ncands);
6956 
6957  ninsertcands = 0;
6958 
6959  /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
6960  * the root envelop detects an overload
6961  */
6962  for( j = 0; j < ncands; ++j )
6963  {
6964  SCIP_BTNODE* leaf;
6965  SCIP_NODEDATA* rootdata;
6966 
6967  /* check if the new job opens a time window which size is so large that it offers more energy than the total
6968  * energy of all candidate jobs. If so we skip that one.
6969  */
6970  if( ((SCIP_Longint) nodedatas[j]->lct - nodedatas[j]->est) * capacity >= totalenergy )
6971  {
6972  /* set the earliest start time to minus one to mark that candidate to be not used */
6973  nodedatas[j]->est = -1;
6974  continue;
6975  }
6976 
6977  /* create search node */
6978  SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)nodedatas[j]) );
6979 
6980  /* insert new node into the theta set and updete the envelops */
6981  SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, &nnodedatas) );
6982  assert(nnodedatas <= 2*nvars);
6983 
6984  /* move the inserted candidates together */
6985  leaves[ninsertcands] = leaf;
6986  ninsertcands++;
6987 
6988  assert(!SCIPbtIsEmpty(tree));
6989  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6990  assert(rootdata != NULL);
6991 
6992  /* check if the theta set envelops exceeds the available capacity */
6993  if( rootdata->enveloptheta > (SCIP_Longint) capacity * nodedatas[j]->lct )
6994  {
6995  SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[j]->lct, j);
6996  (*cutoff) = TRUE;
6997 
6998  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6999  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverload++ );
7000 
7001  break;
7002  }
7003  }
7004 
7005  /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
7006  if( *cutoff )
7007  {
7008  int glbenery;
7009  int est;
7010  int lct;
7011 
7012  glbenery = 0;
7013  est = nodedatas[j]->est;
7014  lct = nodedatas[j]->lct;
7015 
7016  /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
7017  * which led to an overload
7018  */
7019  for( j = j+1; j < ncands; ++j )
7020  {
7021  SCIP_NODEDATA* nodedata;
7022  int duration;
7023  int glbest;
7024  int glblct;
7025 
7026  nodedata = nodedatas[j];
7027  assert(nodedata != NULL);
7028 
7029  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
7030 
7031  /* get latest start time */
7032  glbest = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(nodedata->var));
7033  glblct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
7034 
7035  /* check if parts of the jobs run with the time window defined by the last inserted job */
7036  if( glbest < est )
7037  duration -= (est - glbest);
7038 
7039  if( glblct > lct )
7040  duration -= (glblct - lct);
7041 
7042  if( duration > 0 )
7043  {
7044  glbenery += nodedata->demand * duration;
7045 
7046  if( explanation != NULL )
7047  explanation[nodedata->idx] = TRUE;
7048  }
7049  }
7050 
7051  /* analyze the overload */
7052  SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7053  conshdlrdata->usebdwidening, initialized, explanation) );
7054  }
7055  else if( ninsertcands > 1 && conshdlrdata->efinfer )
7056  {
7057  /* if we have more than one job insterted and edge-finding should be performed we do it */
7058  SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7059  propest, shift, initialized, explanation, nchgbds, cutoff) );
7060  }
7061 
7062  /* free the search nodes data */
7063  for( j = nnodedatas - 1; j >= 0; --j )
7064  {
7065  freeNodedata(scip, &nodedatas[j]);
7066  }
7067 
7068  /* free theta tree */
7069  SCIPbtFree(&tree);
7070 
7071  /* free buffer arrays */
7072  SCIPfreeBufferArray(scip, &leaves);
7073  SCIPfreeBufferArray(scip, &nodedatas);
7074 
7075  return SCIP_OKAY;
7076 }
7077 
7078 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7079  *
7080  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7081  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7082  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7083  */
7084 static
7086  SCIP* scip, /**< SCIP data structure */
7087  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7088  int nvars, /**< number of start time variables (activities) */
7089  SCIP_VAR** vars, /**< array of start time variables */
7090  int* durations, /**< array of durations */
7091  int* demands, /**< array of demands */
7092  int capacity, /**< cumulative capacity */
7093  int hmin, /**< left bound of time axis to be considered (including hmin) */
7094  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7095  SCIP_CONS* cons, /**< constraint which is propagated */
7096  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7097  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7098  int* nchgbds, /**< pointer to store the number of bound changes */
7099  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7100  )
7101 {
7102  /* check if a cutoff was already detected */
7103  if( (*cutoff) )
7104  return SCIP_OKAY;
7105 
7106  /* check if at least the basic overload checking should be preformed */
7107  if( !conshdlrdata->efcheck )
7108  return SCIP_OKAY;
7109 
7110  /* check for overload, which may result in a cutoff */
7111  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7112  cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7113 
7114  /* check if a cutoff was detected */
7115  if( (*cutoff) )
7116  return SCIP_OKAY;
7117 
7118  /* check if bound should be infer */
7119  if( !conshdlrdata->efinfer )
7120  return SCIP_OKAY;
7121 
7122  /* check for overload, which may result in a cutoff */
7123  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7124  cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7125 
7126  return SCIP_OKAY;
7127 }
7128 
7129 /** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7130  * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7131  * event points
7132  */
7133 static
7135  SCIP* scip, /**< SCIP data structure */
7136  int nvars, /**< number of start time variables (activities) */
7137  SCIP_VAR** vars, /**< array of start time variables */
7138  int* durations, /**< array of durations */
7139  int* demands, /**< array of demands */
7140  int capacity, /**< cumulative capacity */
7141  int hmin, /**< left bound of time axis to be considered (including hmin) */
7142  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7143  SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7144  )
7145 {
7146  SCIP_VAR* var;
7147  int* starttimes; /* stores when each job is starting */
7148  int* endtimes; /* stores when each job ends */
7149  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7150  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7151 
7152  int lb;
7153  int ub;
7154  int freecapacity; /* remaining capacity */
7155  int curtime; /* point in time which we are just checking */
7156  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7157  int njobs;
7158  int j;
7159 
7160  assert(scip != NULL);
7161  assert(redundant != NULL);
7162 
7163  (*redundant) = TRUE;
7164 
7165  /* if no activities are associated with this cumulative then this constraint is redundant */
7166  if( nvars == 0 )
7167  return SCIP_OKAY;
7168 
7169  assert(vars != NULL);
7170 
7171  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7172  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7173  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7174  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7175 
7176  njobs = 0;
7177 
7178  /* assign variables, start and endpoints to arrays */
7179  for( j = 0; j < nvars; ++j )
7180  {
7181  assert(durations[j] > 0);
7182  assert(demands[j] > 0);
7183 
7184  var = vars[j];
7185  assert(var != NULL);
7186 
7187  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7188  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7189 
7190  /* check if jobs runs completely outside of the effective time horizon */
7191  if( lb >= hmax || ub + durations[j] <= hmin )
7192  continue;
7193 
7194  starttimes[njobs] = MAX(lb, hmin);
7195  startindices[njobs] = j;
7196 
7197  endtimes[njobs] = MIN(ub + durations[j], hmax);
7198  endindices[njobs] = j;
7199  assert(starttimes[njobs] <= endtimes[njobs]);
7200  njobs++;
7201  }
7202 
7203  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7204  SCIPsortIntInt(starttimes, startindices, njobs);
7205  SCIPsortIntInt(endtimes, endindices, njobs);
7206 
7207  endindex = 0;
7208  freecapacity = capacity;
7209 
7210  /* check each start point of a job whether the capacity is violated or not */
7211  for( j = 0; j < njobs; ++j )
7212  {
7213  curtime = starttimes[j];
7214 
7215  /* stop checking, if time point is above hmax */
7216  if( curtime >= hmax )
7217  break;
7218 
7219  /* subtract all capacity needed up to this point */
7220  freecapacity -= demands[startindices[j]];
7221  while( j+1 < njobs && starttimes[j+1] == curtime )
7222  {
7223  ++j;
7224  freecapacity -= demands[startindices[j]];
7225  }
7226 
7227  /* free all capacity usages of jobs the are no longer running */
7228  while( endtimes[endindex] <= curtime )
7229  {
7230  freecapacity += demands[endindices[endindex]];
7231  ++endindex;
7232  }
7233  assert(freecapacity <= capacity);
7234 
7235  /* check freecapacity to be smaller than zero */
7236  if( freecapacity < 0 && curtime >= hmin )
7237  {
7238  (*redundant) = FALSE;
7239  break;
7240  }
7241  } /*lint --e{850}*/
7242 
7243  /* free all buffer arrays */
7244  SCIPfreeBufferArray(scip, &endindices);
7245  SCIPfreeBufferArray(scip, &startindices);
7246  SCIPfreeBufferArray(scip, &endtimes);
7247  SCIPfreeBufferArray(scip, &starttimes);
7248 
7249  return SCIP_OKAY;
7250 }
7251 
7252 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7253  * completion time
7254  */
7255 static
7257  SCIP* scip, /**< SCIP data structure */
7258  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7259  SCIP_PROFILE* profile, /**< resource profile */
7260  int nvars, /**< number of variables (jobs) */
7261  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7262  int* durations, /**< array containing corresponding durations */
7263  int* demands, /**< array containing corresponding demands */
7264  int capacity, /**< cumulative capacity */
7265  int hmin, /**< left bound of time axis to be considered (including hmin) */
7266  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7267  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7268  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7269  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7270  )
7271 {
7272  int v;
7273 
7274  /* insert all cores */
7275  for( v = 0; v < nvars; ++v )
7276  {
7277  SCIP_VAR* var;
7278  SCIP_Bool infeasible;
7279  int duration;
7280  int demand;
7281  int begin;
7282  int end;
7283  int est;
7284  int lst;
7285  int pos;
7286 
7287  var = vars[v];
7288  assert(var != NULL);
7289  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(var)));
7290  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(var)));
7291 
7292  duration = durations[v];
7293  assert(duration > 0);
7294 
7295  demand = demands[v];
7296  assert(demand > 0);
7297 
7298  /* collect earliest and latest start time */
7299  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7300  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7301 
7302  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7303  if( lst + duration <= hmin || est >= hmax )
7304  continue;
7305 
7306  /* compute core interval w.r.t. effective time horizon */
7307  begin = MAX(hmin, lst);
7308  end = MIN(hmax, est + duration);
7309 
7310  /* check if a core exists */
7311  if( begin >= end )
7312  continue;
7313 
7314  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7315  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7316 
7317  /* insert the core into core resource profile (complexity O(log n)) */
7318  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7319 
7320  /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7321  if( infeasible )
7322  {
7323  assert(begin <= SCIPprofileGetTime(profile, pos));
7324  assert(end > SCIPprofileGetTime(profile, pos));
7325 
7326  /* use conflict analysis to analysis the core insertion which was infeasible */
7327  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7328  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7329 
7330  if( explanation != NULL )
7331  explanation[v] = TRUE;
7332 
7333  (*cutoff) = TRUE;
7334 
7335  /* for the statistic we count the number of times a cutoff was detected due the time-time */
7336  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
7337 
7338  break;
7339  }
7340  }
7341 
7342  return SCIP_OKAY;
7343 }
7344 
7345 /** propagate the cumulative condition */
7346 static
7348  SCIP* scip, /**< SCIP data structure */
7349  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7350  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7351  int nvars, /**< number of start time variables (activities) */
7352  SCIP_VAR** vars, /**< array of start time variables */
7353  int* durations, /**< array of durations */
7354  int* demands, /**< array of demands */
7355  int capacity, /**< cumulative capacity */
7356  int hmin, /**< left bound of time axis to be considered (including hmin) */
7357  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7358  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7359  int* nchgbds, /**< pointer to store the number of bound changes */
7360  SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7361  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7362  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7363  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7364  )
7365 {
7366  SCIP_PROFILE* profile;
7367 
7368  SCIP_RETCODE retcode = SCIP_OKAY;
7369 
7370  assert(nchgbds != NULL);
7371  assert(initialized != NULL);
7372  assert(cutoff != NULL);
7373  assert(!(*cutoff));
7374 
7375  /**@todo avoid always sorting the variable array */
7376 
7377  /* check if the constraint is redundant */
7378  SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7379 
7380  if( *redundant )
7381  return SCIP_OKAY;
7382 
7383  /* create an empty resource profile for profiling the cores of the jobs */
7384  SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7385 
7386  /* create core profile (compulsory parts) */
7387  SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7388  initialized, explanation, cutoff), TERMINATE );
7389 
7390  /* propagate the job cores until nothing else can be detected */
7391  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7392  {
7393  SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7394  nchgbds, initialized, explanation, cutoff), TERMINATE );
7395  }
7396 
7397  /* run edge finding propagator */
7398  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7399  {
7400  SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7401  cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7402  }
7403 
7404  /* run time-table edge-finding propagator */
7405  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7406  {
7407  SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7408  nchgbds, initialized, explanation, cutoff), TERMINATE );
7409  }
7410  /* free resource profile */
7411 TERMINATE:
7412  SCIPprofileFree(&profile);
7413 
7414  return retcode;
7415 }
7416 
7417 /** propagate the cumulative constraint */
7418 static
7420  SCIP* scip, /**< SCIP data structure */
7421  SCIP_CONS* cons, /**< constraint to propagate */
7422  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7423  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7424  int* nchgbds, /**< pointer to store the number of bound changes */
7425  int* ndelconss, /**< pointer to store the number of deleted constraints */
7426  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7427  )
7428 {
7429  SCIP_CONSDATA* consdata;
7430  SCIP_Bool initialized;
7431  SCIP_Bool redundant;
7432  int oldnchgbds;
7433 
7434  assert(scip != NULL);
7435  assert(cons != NULL);
7436 
7437  consdata = SCIPconsGetData(cons);
7438  assert(consdata != NULL);
7439 
7440  oldnchgbds = *nchgbds;
7441  initialized = FALSE;
7442  redundant = FALSE;
7443 
7444  if( SCIPconsIsDeleted(cons) )
7445  {
7446  assert(SCIPinProbing(scip));
7447  return SCIP_OKAY;
7448  }
7449 
7450  /* if the constraint marked to be propagated, do nothing */
7451  if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7452  return SCIP_OKAY;
7453 
7454  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7455  consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7456  consdata->hmin, consdata->hmax, cons,
7457  nchgbds, &redundant, &initialized, NULL, cutoff) );
7458 
7459  if( redundant )
7460  {
7461  SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7462  SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7463 
7464  if( !SCIPinProbing(scip) )
7465  {
7466  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7467  (*ndelconss)++;
7468  }
7469  }
7470  else
7471  {
7472  if( initialized )
7473  {
7474  /* run conflict analysis since it was initialized */
7475  assert(*cutoff == TRUE);
7476  SCIPdebugMsg(scip, "start conflict analysis\n");
7477  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7478  }
7479 
7480  /* if successful, reset age of constraint */
7481  if( *cutoff || *nchgbds > oldnchgbds )
7482  {
7483  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7484  }
7485  else
7486  {
7487  /* mark the constraint to be propagated */
7488  consdata->propagated = TRUE;
7489  }
7490  }
7491 
7492  return SCIP_OKAY;
7493 }
7494 
7495 /** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7496  * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7497  * be realize as domain reduction. Otherwise we do nothing
7498  */
7499 static
7501  SCIP* scip, /**< SCIP data structure */
7502  SCIP_VAR** vars, /**< problem variables */
7503  int nvars, /**< number of problem variables */
7504  int probingpos, /**< variable number to apply probing on */
7505  SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7506  SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7507  SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7508  SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7509  SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7510  SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7511  SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7512  SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7513  SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7514  SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7515  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7516  SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7517  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7518  )
7519 {
7520  SCIP_VAR* var;
7521  SCIP_Bool tightened;
7522 
7523  assert(probingpos >= 0);
7524  assert(probingpos < nvars);
7525  assert(success != NULL);
7526  assert(cutoff != NULL);
7527 
7528  var = vars[probingpos];
7529  assert(var != NULL);
7530  assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7531  assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7532  assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7533  assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7534 
7535  (*success) = FALSE;
7536 
7537  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7538  return SCIP_OKAY;
7539 
7540  /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7541  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7542  leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7543 
7544  if( (*cutoff) )
7545  {
7546  /* note that cutoff may occur if presolving has not been executed fully */
7547  SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7548 
7549  if( tightened )
7550  {
7551  (*success) =TRUE;
7552  (*nfixedvars)++;
7553  }
7554 
7555  return SCIP_OKAY;
7556  }
7557 
7558  /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7559  * presolving has not been executed fully
7560  */
7561  if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7562  {
7563  /* note that cutoff may occur if presolving has not been executed fully */
7564  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7565 
7566  if( tightened )
7567  {
7568  (*success) = TRUE;
7569  (*nfixedvars)++;
7570  }
7571 
7572  return SCIP_OKAY;
7573  }
7574 
7575  /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7576  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7577  rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7578 
7579  if( (*cutoff) )
7580  {
7581  /* note that cutoff may occur if presolving has not been executed fully */
7582  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7583 
7584  if( tightened )
7585  {
7586  (*success) =TRUE;
7587  (*nfixedvars)++;
7588  }
7589 
7590  return SCIP_OKAY;
7591  }
7592 
7593  return SCIP_OKAY;
7594 }
7595 
7596 /** is it possible, to round variable down w.r.t. objective function */
7597 static
7599  SCIP* scip, /**< SCIP data structure */
7600  SCIP_VAR* var, /**< problem variable */
7601  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7602  )
7603 {
7604  SCIP_Real objval;
7605  int scalar;
7606 
7607  assert(roundable != NULL);
7608 
7609  *roundable = TRUE;
7610 
7611  /* a fixed variable can be definition always be safely rounded */
7613  return SCIP_OKAY;
7614 
7615  /* in case the variable is not active we need to check the object coefficient of the active variable */
7616  if( !SCIPvarIsActive(var) )
7617  {
7618  SCIP_VAR* actvar;
7619  int constant;
7620 
7621  actvar = var;
7622 
7623  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7624  assert(scalar != 0);
7625 
7626  objval = scalar * SCIPvarGetObj(actvar);
7627  }
7628  else
7629  {
7630  scalar = 1;
7631  objval = SCIPvarGetObj(var);
7632  }
7633 
7634  /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7635  * (the transformed problem is always a minimization problem)
7636  *
7637  * @note that we need to check this condition w.r.t. active variable space
7638  */
7639  if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7640  *roundable = FALSE;
7641 
7642  return SCIP_OKAY;
7643 }
7644 
7645 /** is it possible, to round variable up w.r.t. objective function */
7646 static
7648  SCIP* scip, /**< SCIP data structure */
7649  SCIP_VAR* var, /**< problem variable */
7650  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7651  )
7652 {
7653  SCIP_Real objval;
7654  int scalar;
7655 
7656  assert(roundable != NULL);
7657 
7658  *roundable = TRUE;
7659 
7660  /* a fixed variable can be definition always be safely rounded */
7662  return SCIP_OKAY;
7663 
7664  /* in case the variable is not active we need to check the object coefficient of the active variable */
7665  if( !SCIPvarIsActive(var) )
7666  {
7667  SCIP_VAR* actvar;
7668  int constant;
7669 
7670  actvar = var;
7671 
7672  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7673  assert(scalar != 0);
7674 
7675  objval = scalar * SCIPvarGetObj(actvar);
7676  }
7677  else
7678  {
7679  scalar = 1;
7680  objval = SCIPvarGetObj(var);
7681  }
7682 
7683  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7684  * (the transformed problem is always a minimization problem)
7685  *
7686  * @note that we need to check this condition w.r.t. active variable space
7687  */
7688  if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7689  *roundable = FALSE;
7690 
7691  return SCIP_OKAY;
7692 }
7693 
7694 /** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7695  * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7696  * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7697  * the only one locking this variable in the corresponding direction.
7698  */
7699 static
7701  SCIP* scip, /**< SCIP data structure */
7702  SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7703  int nconss, /**< number of cumulative constraints */
7704  SCIP_Bool local, /**< use local bounds effective horizon? */
7705  int* alternativelbs, /**< alternative lower bounds */
7706  int* alternativeubs, /**< alternative lower bounds */
7707  int* downlocks, /**< number of constraints with down lock participating by the computation */
7708  int* uplocks /**< number of constraints with up lock participating by the computation */
7709  )
7710 {
7711  int nvars;
7712  int c;
7713  int v;
7714 
7715  for( c = 0; c < nconss; ++c )
7716  {
7717  SCIP_CONSDATA* consdata;
7718  SCIP_CONS* cons;
7719  SCIP_VAR* var;
7720  int hmin;
7721  int hmax;
7722 
7723  cons = conss[c];
7724  assert(cons != NULL);
7725 
7726  /* ignore constraints which are already deletet and those which are not check constraints */
7727  if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7728  continue;
7729 
7730  consdata = SCIPconsGetData(cons);
7731  assert(consdata != NULL);
7732  assert(consdata->nvars > 1);
7733 
7734  /* compute the hmin and hmax */
7735  if( local )
7736  {
7737  SCIP_PROFILE* profile;
7738  SCIP_RETCODE retcode;
7739 
7740  /* create empty resource profile with infinity resource capacity */
7741  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7742 
7743  /* create worst case resource profile */
7744  retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
7745 
7746  hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7747  hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7748 
7749  /* free worst case profile */
7750  SCIPprofileFree(&profile);
7751 
7752  if( retcode != SCIP_OKAY )
7753  return retcode;
7754  }
7755  else
7756  {
7757  hmin = consdata->hmin;
7758  hmax = consdata->hmax;
7759  }
7760 
7761  consdata = SCIPconsGetData(cons);
7762  assert(consdata != NULL);
7763 
7764  nvars = consdata->nvars;
7765 
7766  for( v = 0; v < nvars; ++v )
7767  {
7768  int scalar;
7769  int constant;
7770  int idx;
7771 
7772  var = consdata->vars[v];
7773  assert(var != NULL);
7774 
7775  /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7776  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR);
7777 
7778  /* ignore variable locally fixed variables */
7779  if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7780  continue;
7781 
7782  SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7783  idx = SCIPvarGetProbindex(var);
7784  assert(idx >= 0);
7785 
7786  /* first check lower bound fixing */
7787  if( consdata->downlocks[v] )
7788  {
7789  int ect;
7790  int est;
7791 
7792  /* the variable has a down locked */
7793  est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7794  ect = est + consdata->durations[v];
7795 
7796  if( ect <= hmin || hmin >= hmax )
7797  downlocks[idx]++;
7798  else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7799  {
7800  alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7801  downlocks[idx]++;
7802  }
7803  }
7804 
7805  /* second check upper bound fixing */
7806  if( consdata->uplocks[v] )
7807  {
7808  int duration;
7809  int lct;
7810  int lst;
7811 
7812  duration = consdata->durations[v];
7813 
7814  /* the variable has a up lock locked */
7815  lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7816  lct = lst + duration;
7817 
7818  if( lst >= hmax || hmin >= hmax )
7819  uplocks[idx]++;
7820  else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7821  {
7822  alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7823  uplocks[idx]++;
7824  }
7825  }
7826  }
7827  }
7828 
7829  return SCIP_OKAY;
7830 }
7831 
7832 /** apply all fixings which are given by the alternative bounds */
7833 static
7835  SCIP* scip, /**< SCIP data structure */
7836  SCIP_VAR** vars, /**< array of active variables */
7837  int nvars, /**< number of active variables */
7838  int* alternativelbs, /**< alternative lower bounds */
7839  int* alternativeubs, /**< alternative lower bounds */
7840  int* downlocks, /**< number of constraints with down lock participating by the computation */
7841  int* uplocks, /**< number of constraints with up lock participating by the computation */
7842  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7843  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7844  )
7845 {
7846  SCIP_Real* downimpllbs;
7847  SCIP_Real* downimplubs;
7848  SCIP_Real* downproplbs;
7849  SCIP_Real* downpropubs;
7850  SCIP_Real* upimpllbs;
7851  SCIP_Real* upimplubs;
7852  SCIP_Real* upproplbs;
7853  SCIP_Real* uppropubs;
7854  int v;
7855 
7856  /* get temporary memory for storing probing results */
7857  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7858  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7859  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7860  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7861  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7862  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7863  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7864  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7865 
7866  for( v = 0; v < nvars; ++v )
7867  {
7868  SCIP_VAR* var;
7869  SCIP_Bool infeasible;
7870  SCIP_Bool fixed;
7871  SCIP_Bool roundable;
7872  int ub;
7873  int lb;
7874 
7875  var = vars[v];
7876  assert(var != NULL);
7877 
7878  /* ignore variables for which no alternative bounds have been computed */
7879  if( alternativelbs[v] == INT_MAX && alternativeubs[v] == INT_MIN )
7880  continue;
7881 
7882  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7883  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7884 
7885  /* ignore fixed variables */
7886  if( ub - lb <= 0 )
7887  continue;
7888 
7889  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
7890  {
7891  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7892 
7893  if( roundable )
7894  {
7895  if( alternativelbs[v] > ub )
7896  {
7897  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7898  assert(!infeasible);
7899  assert(fixed);
7900 
7901  (*nfixedvars)++;
7902 
7903  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7904  * constraints
7905  */
7906  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7907  }
7908  else
7909  {
7910  SCIP_Bool success;
7911 
7912  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7913  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7914  * infeasible we can apply the dual reduction; otherwise we do nothing
7915  */
7916  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7917  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7918  nfixedvars, &success, cutoff) );
7919 
7920  if( success )
7921  {
7922  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7923  }
7924  }
7925  }
7926  }
7927 
7928  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7929  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7930 
7931  /* ignore fixed variables */
7932  if( ub - lb <= 0 )
7933  continue;
7934 
7935  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
7936  {
7937  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7938 
7939  if( roundable )
7940  {
7941  if( alternativeubs[v] < lb )
7942  {
7943  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
7944  assert(!infeasible);
7945  assert(fixed);
7946 
7947  (*nfixedvars)++;
7948 
7949  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7950  * constraints
7951  */
7952  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7953  }
7954  else
7955  {
7956  SCIP_Bool success;
7957 
7958  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7959  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7960  * infeasible we can apply the dual reduction; otherwise we do nothing
7961  */
7962  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
7963  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7964  nfixedvars, &success, cutoff) );
7965 
7966  if( success )
7967  {
7968  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7969  }
7970  }
7971  }
7972  }
7973  }
7974 
7975  /* free temporary memory */
7976  SCIPfreeBufferArray(scip, &uppropubs);
7977  SCIPfreeBufferArray(scip, &upproplbs);
7978  SCIPfreeBufferArray(scip, &upimplubs);
7979  SCIPfreeBufferArray(scip, &upimpllbs);
7980  SCIPfreeBufferArray(scip, &downpropubs);
7981  SCIPfreeBufferArray(scip, &downproplbs);
7982  SCIPfreeBufferArray(scip, &downimplubs);
7983  SCIPfreeBufferArray(scip, &downimpllbs);
7984 
7985  return SCIP_OKAY;
7986 }
7987 
7988 /** propagate all constraints together */
7989 static
7991  SCIP* scip, /**< SCIP data structure */
7992  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7993  SCIP_CONS** conss, /**< all cumulative constraint */
7994  int nconss, /**< number of cumulative constraints */
7995  SCIP_Bool local, /**< use local bounds effective horizon? */
7996  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7997  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
7998  SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
7999  )
8000 { /*lint --e{715}*/
8001  SCIP_VAR** vars;
8002  int* downlocks;
8003  int* uplocks;
8004  int* alternativelbs;
8005  int* alternativeubs;
8006  int oldnfixedvars;
8007  int nvars;
8008  int v;
8009 
8010  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
8011  return SCIP_OKAY;
8012 
8013  nvars = SCIPgetNVars(scip);
8014  oldnfixedvars = *nfixedvars;
8015 
8016  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
8017  SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
8018  SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
8019  SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
8020  SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
8021 
8022  /* initialize arrays */
8023  for( v = 0; v < nvars; ++v )
8024  {
8025  downlocks[v] = 0;
8026  uplocks[v] = 0;
8027  alternativelbs[v] = INT_MAX;
8028  alternativeubs[v] = INT_MIN;
8029  }
8030 
8031  /* compute alternative bounds */
8032  SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
8033 
8034  /* apply fixing which result of the alternative bounds directly */
8035  SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
8036  nfixedvars, cutoff) );
8037 
8038  if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
8039  {
8040  SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
8041  }
8042 
8043  /* free all buffers */
8044  SCIPfreeBufferArray(scip, &alternativeubs);
8045  SCIPfreeBufferArray(scip, &alternativelbs);
8046  SCIPfreeBufferArray(scip, &uplocks);
8047  SCIPfreeBufferArray(scip, &downlocks);
8048  SCIPfreeBufferArray(scip, &vars);
8049 
8050  return SCIP_OKAY;
8051 }
8052 
8053 /**@} */
8054 
8055 /**@name Linear relaxations
8056  *
8057  * @{
8058  */
8059 
8060 /** creates covering cuts for jobs violating resource constraints */
8061 static
8063  SCIP* scip, /**< SCIP data structure */
8064  SCIP_CONS* cons, /**< constraint to be checked */
8065  int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8066  int time /**< at this point in time covering constraints are valid */
8067  )
8068 {
8069  SCIP_CONSDATA* consdata;
8070  SCIP_ROW* row;
8071  int* flexibleids;
8072  int* demands;
8073 
8074  char rowname[SCIP_MAXSTRLEN];
8075 
8076  int remainingcap;
8077  int smallcoversize; /* size of a small cover */
8078  int bigcoversize; /* size of a big cover */
8079  int nvars;
8080 
8081  int nflexible;
8082  int sumdemand; /* demand of all jobs up to a certain index */
8083  int j;
8084 
8085  assert(cons != NULL);
8086 
8087  /* get constraint data structure */
8088  consdata = SCIPconsGetData(cons);
8089  assert(consdata != NULL );
8090 
8091  nvars = consdata->nvars;
8092 
8093  /* sort jobs according to demands */
8094  SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8095  SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8096 
8097  nflexible = 0;
8098  remainingcap = consdata->capacity;
8099 
8100  /* get all jobs intersecting point 'time' with their bounds */
8101  for( j = 0; j < nvars; ++j )
8102  {
8103  int ub;
8104 
8105  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8106 
8107  /* only add jobs to array if they intersect with point 'time' */
8108  if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8109  {
8110  /* if job is fixed, capacity has to be decreased */
8111  if( startvalues[j] == ub )
8112  {
8113  remainingcap -= consdata->demands[j];
8114  }
8115  else
8116  {
8117  demands[nflexible] = consdata->demands[j];
8118  flexibleids[nflexible] = j;
8119  ++nflexible;
8120  }
8121  }
8122  }
8123  assert(remainingcap >= 0);
8124 
8125  /* sort demands and job ids */
8126  SCIPsortIntInt(demands, flexibleids, nflexible);
8127 
8128  /*
8129  * version 1:
8130  * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8131  * erzeuge cover constraint
8132  *
8133  */
8134 
8135  /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8136  sumdemand = 0;
8137  j = 0;
8138 
8139  while( j < nflexible && sumdemand <= remainingcap )
8140  {
8141  sumdemand += demands[j];
8142  j++;
8143  }
8144 
8145  /* j jobs form a conflict, set coversize to 'j - 1' */
8146  bigcoversize = j-1;
8147  assert(sumdemand > remainingcap);
8148  assert(bigcoversize < nflexible);
8149 
8150  /* - create a row for all jobs and their binary variables.
8151  * - at most coversize many binary variables of jobs can be set to one
8152  */
8153 
8154  /* construct row name */
8155  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8156  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8157  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8158  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8159 
8160  for( j = 0; j < nflexible; ++j )
8161  {
8162  SCIP_VAR** binvars;
8163  int* vals;
8164  int nbinvars;
8165  int idx;
8166  int start;
8167  int end;
8168  int lb;
8169  int ub;
8170  int b;
8171 
8172  idx = flexibleids[j];
8173 
8174  /* get and add binvars into var array */
8175  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8176  assert(nbinvars != 0);
8177 
8178  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8179  assert(vals != NULL);
8180 
8181  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8182  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8183 
8184  /* compute start and finishing time */
8185  start = time - consdata->durations[idx] + 1;
8186  end = MIN(time, ub);
8187 
8188  /* add all neccessary binary variables */
8189  for( b = 0; b < nbinvars; ++b )
8190  {
8191  if( vals[b] < start || vals[b] < lb )
8192  continue;
8193 
8194  if( vals[b] > end )
8195  break;
8196 
8197  assert(binvars[b] != NULL);
8198  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8199  }
8200  }
8201 
8202  /* insert and release row */
8203  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8204 
8205  if( consdata->bcoverrowssize == 0 )
8206  {
8207  consdata->bcoverrowssize = 10;
8208  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8209  }
8210  if( consdata->nbcoverrows == consdata->bcoverrowssize )
8211  {
8212  consdata->bcoverrowssize *= 2;
8213  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8214  }
8215 
8216  consdata->bcoverrows[consdata->nbcoverrows] = row;
8217  consdata->nbcoverrows++;
8218 
8219  /*
8220  * version 2:
8221  * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8222  * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8223  */
8224  /* find maximum number of jobs that can run in parallel (= coversize -1) */
8225  sumdemand = 0;
8226  j = nflexible -1;
8227  while( sumdemand <= remainingcap )
8228  {
8229  assert(j >= 0);
8230  sumdemand += demands[j];
8231  j--;
8232  }
8233 
8234  smallcoversize = nflexible - (j + 1) - 1;
8235  while( j > 0 && demands[j] == demands[nflexible-1] )
8236  --j;
8237 
8238  assert(smallcoversize < nflexible);
8239 
8240  if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8241  {
8242  /* construct row name */
8243  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8244  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8245  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8246  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8247 
8248  /* filter binary variables for each unfixed job */
8249  for( j = j + 1; j < nflexible; ++j )
8250  {
8251  SCIP_VAR** binvars;
8252  int* vals;
8253  int nbinvars;
8254  int idx;
8255  int start;
8256  int end;
8257  int lb;
8258  int ub;
8259  int b;
8260 
8261  idx = flexibleids[j];
8262 
8263  /* get and add binvars into var array */
8264  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8265  assert(nbinvars != 0);
8266 
8267  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8268  assert(vals != NULL);
8269 
8270  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8271  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8272 
8273  /* compute start and finishing time */
8274  start = time - consdata->durations[idx] + 1;
8275  end = MIN(time, ub);
8276 
8277  /* add all neccessary binary variables */
8278  for( b = 0; b < nbinvars; ++b )
8279  {
8280  if( vals[b] < start || vals[b] < lb )
8281  continue;
8282 
8283  if( vals[b] > end )
8284  break;
8285 
8286  assert(binvars[b] != NULL);
8287  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8288  }
8289  }
8290 
8291  /* insert and release row */
8292  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8293  if( consdata->scoverrowssize == 0 )
8294  {
8295  consdata->scoverrowssize = 10;
8296  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8297  }
8298  if( consdata->nscoverrows == consdata->scoverrowssize )
8299  {
8300  consdata->scoverrowssize *= 2;
8301  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8302  }
8303 
8304  consdata->scoverrows[consdata->nscoverrows] = row;
8305  consdata->nscoverrows++;
8306  }
8307 
8308  /* free buffer arrays */
8309  SCIPfreeBufferArray(scip, &flexibleids);
8310  SCIPfreeBufferArray(scip, &demands);
8311 
8312  return SCIP_OKAY;
8313 }
8314 
8315 /** method to construct cover cuts for all points in time */
8316 static
8318  SCIP* scip, /**< SCIP data structure */
8319  SCIP_CONS* cons /**< constraint to be separated */
8320  )
8321 {
8322  SCIP_CONSDATA* consdata;
8323 
8324  int* startvalues; /* stores when each job is starting */
8325  int* endvalues; /* stores when each job ends */
8326  int* startvaluessorted; /* stores when each job is starting */
8327  int* endvaluessorted; /* stores when each job ends */
8328  int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8329  int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8330 
8331  int nvars; /* number of jobs for this constraint */
8332  int freecapacity; /* remaining capacity */
8333  int curtime; /* point in time which we are just checking */
8334  int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8335 
8336  int hmin;
8337  int hmax;
8338 
8339  int j;
8340  int t;
8341 
8342  assert(scip != NULL);
8343  assert(cons != NULL);
8344 
8345  consdata = SCIPconsGetData(cons);
8346  assert(consdata != NULL);
8347 
8348  /* if no activities are associated with this resource then this constraint is redundant */
8349  if( consdata->vars == NULL )
8350  return SCIP_OKAY;
8351 
8352  nvars = consdata->nvars;
8353  hmin = consdata->hmin;
8354  hmax = consdata->hmax;
8355 
8356  SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8357  SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8358  SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8359  SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8360  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8361  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8362 
8363  /* assign start and endpoints to arrays */
8364  for ( j = 0; j < nvars; ++j )
8365  {
8366  startvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8367  startvaluessorted[j] = startvalues[j];
8368 
8369  endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8370  endvaluessorted[j] = endvalues[j];
8371 
8372  startindices[j] = j;
8373  endindices[j] = j;
8374  }
8375 
8376  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8377  * (and sort the indices in the same way) */
8378  SCIPsortIntInt(startvaluessorted, startindices, nvars);
8379  SCIPsortIntInt(endvaluessorted, endindices, nvars);
8380 
8381  endidx = 0;
8382  freecapacity = consdata->capacity;
8383 
8384  /* check each startpoint of a job whether the capacity is kept or not */
8385  for( j = 0; j < nvars; ++j )
8386  {
8387  curtime = startvaluessorted[j];
8388  if( curtime >= hmax )
8389  break;
8390 
8391  /* subtract all capacity needed up to this point */
8392  freecapacity -= consdata->demands[startindices[j]];
8393 
8394  while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8395  {
8396  ++j;
8397  freecapacity -= consdata->demands[startindices[j]];
8398  }
8399 
8400  /* free all capacity usages of jobs the are no longer running */
8401  while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8402  {
8403  freecapacity += consdata->demands[endindices[endidx]];
8404  ++endidx;
8405  }
8406 
8407  assert(freecapacity <= consdata->capacity);
8408  assert(endidx <= nvars);
8409 
8410  /* --> endindex - points to the next job which will finish
8411  * j - points to the last job that has been released
8412  */
8413 
8414  /* check freecapacity to be smaller than zero
8415  * then we will add cover constraints to the MIP
8416  */
8417  if( freecapacity < 0 && curtime >= hmin )
8418  {
8419  int nextprofilechange;
8420 
8421  /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8422  if( j < nvars-1 )
8423  nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8424  else
8425  nextprofilechange = endvaluessorted[endidx];
8426 
8427  nextprofilechange = MIN(nextprofilechange, hmax);
8428 
8429  for( t = curtime; t < nextprofilechange; ++t )
8430  {
8431  SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8432 
8433  /* create covering constraint */
8434  SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8435  }
8436  } /* end if freecapacity > 0 */
8437  } /*lint --e{850}*/
8438 
8439  consdata->covercuts = TRUE;
8440 
8441  /* free all buffer arrays */
8442  SCIPfreeBufferArray(scip, &endindices);
8443  SCIPfreeBufferArray(scip, &startindices);
8444  SCIPfreeBufferArray(scip, &endvaluessorted);
8445  SCIPfreeBufferArray(scip, &startvaluessorted);
8446  SCIPfreeBufferArray(scip, &endvalues);
8447  SCIPfreeBufferArray(scip, &startvalues);
8448 
8449  return SCIP_OKAY;
8450 }
8451 
8452 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8453  * constraint
8454  */
8455 static
8457  SCIP* scip, /**< SCIP data structure */
8458  SCIP_CONS* cons, /**< constraint to be checked */
8459  int* startindices, /**< permutation with rspect to the start times */
8460  int curtime, /**< current point in time */
8461  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8462  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8463  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8464  )
8465 {
8466  SCIP_CONSDATA* consdata;
8467  SCIP_VAR** binvars;
8468  int* coefs;
8469  int nbinvars;
8470  char name[SCIP_MAXSTRLEN];
8471  int capacity;
8472  int b;
8473 
8474  assert(nstarted > nfinished);
8475 
8476  consdata = SCIPconsGetData(cons);
8477  assert(consdata != NULL);
8478  assert(consdata->nvars > 0);
8479 
8480  capacity = consdata->capacity;
8481  assert(capacity > 0);
8482 
8483  nbinvars = 0;
8484  SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8485 
8486  /* construct row name */
8487  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8488 
8489  if( cutsasconss )
8490  {
8491  SCIP_CONS* lincons;
8492 
8493  /* create knapsack constraint for the given time point */
8494  SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8495  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) );
8496 
8497  for( b = 0; b < nbinvars; ++b )
8498  {
8499  SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8500  }
8501 
8502  /* add and release the new constraint */
8503  SCIP_CALL( SCIPaddCons(scip, lincons) );
8504  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8505  }
8506  else
8507  {
8508  SCIP_ROW* row;
8509 
8510  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8511  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8512 
8513  for( b = 0; b < nbinvars; ++b )
8514  {
8515  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8516  }
8517 
8518  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8519  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8520 
8521  if( consdata->demandrowssize == 0 )
8522  {
8523  consdata->demandrowssize = 10;
8524  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8525  }
8526  if( consdata->ndemandrows == consdata->demandrowssize )
8527  {
8528  consdata->demandrowssize *= 2;
8529  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8530  }
8531 
8532  consdata->demandrows[consdata->ndemandrows] = row;
8533  consdata->ndemandrows++;
8534  }
8535 
8536  SCIPfreeBufferArrayNull(scip, &binvars);
8537  SCIPfreeBufferArrayNull(scip, &coefs);
8538 
8539  return SCIP_OKAY;
8540 }
8541 
8542 /** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8543  * row
8544  */
8545 static
8547  SCIP* scip, /**< SCIP data structure */
8548  SCIP_CONS* cons, /**< constraint to be checked */
8549  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8550  )
8551 {
8552  SCIP_CONSDATA* consdata;
8553 
8554  int* starttimes; /* stores when each job is starting */
8555  int* endtimes; /* stores when each job ends */
8556  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8557  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8558 
8559  int nvars; /* number of activities for this constraint */
8560  int freecapacity; /* remaining capacity */
8561  int curtime; /* point in time which we are just checking */
8562  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8563 
8564  int hmin;
8565  int hmax;
8566 
8567  int j;
8568 
8569  assert(scip != NULL);
8570  assert(cons != NULL);
8571 
8572  consdata = SCIPconsGetData(cons);
8573  assert(consdata != NULL);
8574 
8575  nvars = consdata->nvars;
8576 
8577  /* if no activities are associated with this cumulative then this constraint is redundant */
8578  if( nvars == 0 )
8579  return SCIP_OKAY;
8580 
8581  assert(consdata->vars != NULL);
8582 
8583  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8584  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8585  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8586  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8587 
8588  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8589  SCIPconsGetName(cons), nvars);
8590 
8591  /* create event point arrays */
8592  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8593  starttimes, endtimes, startindices, endindices, FALSE);
8594 
8595  endindex = 0;
8596  freecapacity = consdata->capacity;
8597  hmin = consdata->hmin;
8598  hmax = consdata->hmax;
8599 
8600  /* check each startpoint of a job whether the capacity is kept or not */
8601  for( j = 0; j < nvars; ++j )
8602  {
8603  curtime = starttimes[j];
8604  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8605 
8606  if( curtime >= hmax )
8607  break;
8608 
8609  /* remove the capacity requirments for all job which start at the curtime */
8610  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8611 
8612  /* add the capacity requirments for all job which end at the curtime */
8613  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8614 
8615  assert(freecapacity <= consdata->capacity);
8616  assert(endindex <= nvars);
8617 
8618  /* endindex - points to the next job which will finish */
8619  /* j - points to the last job that has been released */
8620 
8621  /* if free capacity is smaller than zero, then add rows to the LP */
8622  if( freecapacity < 0 && curtime >= hmin )
8623  {
8624  int nextstarttime;
8625  int t;
8626 
8627  /* step forward until next job is released and see whether capacity constraint is met or not */
8628  if( j < nvars-1 )
8629  nextstarttime = starttimes[j+1];
8630  else
8631  nextstarttime = endtimes[nvars-1];
8632 
8633  nextstarttime = MIN(nextstarttime, hmax);
8634 
8635  /* create capacity restriction row for current event point */
8636  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8637 
8638  /* create for all points in time between the current event point and next start event point a row if the free
8639  * capacity is still smaller than zero */
8640  for( t = curtime+1 ; t < nextstarttime; ++t )
8641  {
8642  /* add the capacity requirments for all job which end at the curtime */
8643  addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8644 
8645  if( freecapacity < 0 )
8646  {
8647  /* add constraint */
8648  SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8649 
8650  /* create capacity restriction row */
8651  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8652  }
8653  else
8654  break;
8655  }
8656  }
8657  } /*lint --e{850}*/
8658 
8659  /* free all buffer arrays */
8660  SCIPfreeBufferArray(scip, &endindices);
8661  SCIPfreeBufferArray(scip, &startindices);
8662  SCIPfreeBufferArray(scip, &endtimes);
8663  SCIPfreeBufferArray(scip, &starttimes);
8664 
8665  return SCIP_OKAY;
8666 }
8667 
8668 /** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8669  * capacity is larger than the capacity of the cumulative constraint
8670  * - for each necessary point in time:
8671  *
8672  * sum_j sum_t demand_j * x_{j,t} <= capacity
8673  *
8674  * where x(j,t) is the binary variables of job j at time t
8675  */
8676 static
8678  SCIP* scip, /**< SCIP data structure */
8679  SCIP_CONS* cons, /**< cumulative constraint */
8680  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8681  )
8682 {
8683  SCIP_CONSDATA* consdata;
8684 
8685  consdata = SCIPconsGetData(cons);
8686  assert(consdata != NULL);
8687  assert(consdata->demandrows == NULL);
8688  assert(consdata->ndemandrows == 0);
8689 
8690  /* collect the linking constraints */
8691  if( consdata->linkingconss == NULL )
8692  {
8693  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8694  }
8695 
8696  SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8697 
8698  /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8699  if( cutsasconss )
8700  {
8701  if( SCIPconsIsInitial(cons) )
8702  {
8703  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
8704  }
8705  if( SCIPconsIsSeparated(cons) )
8706  {
8707  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
8708  }
8709  if( SCIPconsIsEnforced(cons) )
8710  {
8711  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
8712  }
8713  }
8714 
8715  return SCIP_OKAY;
8716 }
8717 
8718 /** adds linear relaxation of cumulative constraint to the LP */
8719 static
8721  SCIP* scip, /**< SCIP data structure */
8722  SCIP_CONS* cons, /**< cumulative constraint */
8723  SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
8724  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
8725  )
8726 {
8727  SCIP_CONSDATA* consdata;
8728  int r;
8729 
8730  consdata = SCIPconsGetData(cons);
8731  assert(consdata != NULL);
8732 
8733  if( consdata->demandrows == NULL )
8734  {
8735  assert(consdata->ndemandrows == 0);
8736 
8737  SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8738 
8739  return SCIP_OKAY;
8740  }
8741 
8742  for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8743  {
8744  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8745  {
8746  assert(consdata->demandrows[r] != NULL);
8747  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
8748  }
8749  }
8750 
8751  return SCIP_OKAY;
8752 }
8753 
8754 /** checks constraint for violation, and adds it as a cut if possible */
8755 static
8757  SCIP* scip, /**< SCIP data structure */
8758  SCIP_CONS* cons, /**< cumulative constraint to be separated */
8759  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8760  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8761  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8762  )
8763 { /*lint --e{715}*/
8764  SCIP_CONSDATA* consdata;
8765  int ncuts;
8766  int r;
8767 
8768  assert(scip != NULL);
8769  assert(cons != NULL);
8770  assert(separated != NULL);
8771  assert(cutoff != NULL);
8772 
8773  *separated = FALSE;
8774  *cutoff = FALSE;
8775 
8776  consdata = SCIPconsGetData(cons);
8777  assert(consdata != NULL);
8778 
8779  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8780 
8781  if( consdata->demandrows == NULL )
8782  {
8783  assert(consdata->ndemandrows == 0);
8784 
8785  SCIP_CALL( createRelaxation(scip, cons, FALSE) );
8786 
8787  return SCIP_OKAY;
8788  }
8789 
8790  ncuts = 0;
8791 
8792  /* check each row that is not contained in LP */
8793  for( r = 0; r < consdata->ndemandrows; ++r )
8794  {
8795  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8796  {
8797  SCIP_Real feasibility;
8798 
8799  if( sol != NULL )
8800  feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8801  else
8802  feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8803 
8804  if( SCIPisFeasNegative(scip, feasibility) )
8805  {
8806  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
8807  if ( *cutoff )
8808  {
8809  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8810  return SCIP_OKAY;
8811  }
8812  *separated = TRUE;
8813  ncuts++;
8814  }
8815  }
8816  }
8817 
8818  if( ncuts > 0 )
8819  {
8820  SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8821 
8822  /* if successful, reset age of constraint */
8823  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8824  (*separated) = TRUE;
8825  }
8826 
8827  return SCIP_OKAY;
8828 }
8829 
8830 /** checks constraint for violation, and adds it as a cut if possible */
8831 static
8833  SCIP* scip, /**< SCIP data structure */
8834  SCIP_CONS* cons, /**< logic or constraint to be separated */
8835  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8836  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8837  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8838  )
8839 {
8840  SCIP_CONSDATA* consdata;
8841  SCIP_ROW* row;
8842  SCIP_Real minfeasibility;
8843  int r;
8844 
8845  assert(scip != NULL);
8846  assert(cons != NULL);
8847  assert(separated != NULL);
8848  assert(cutoff != NULL);
8849 
8850  *separated = FALSE;
8851  *cutoff = FALSE;
8852 
8853  consdata = SCIPconsGetData(cons);
8854  assert(consdata != NULL);
8855 
8856  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8857 
8858  /* collect the linking constraints */
8859  if( consdata->linkingconss == NULL )
8860  {
8861  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8862  }
8863 
8864  if( !consdata->covercuts )
8865  {
8866  SCIP_CALL( createCoverCuts(scip, cons) );
8867  }
8868 
8869  row = NULL;
8870  minfeasibility = SCIPinfinity(scip);
8871 
8872  /* check each row of small covers that is not contained in LP */
8873  for( r = 0; r < consdata->nscoverrows; ++r )
8874  {
8875  if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8876  {
8877  SCIP_Real feasibility;
8878 
8879  assert(consdata->scoverrows[r] != NULL);
8880  if( sol != NULL )
8881  feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8882  else
8883  feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8884 
8885  if( minfeasibility > feasibility )
8886  {
8887  minfeasibility = feasibility;
8888  row = consdata->scoverrows[r];
8889  }
8890  }
8891  }
8892 
8893  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8894 
8895  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8896  {
8897  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8898  SCIPconsGetName(cons), minfeasibility);
8899 
8900  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8901  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8902  if ( *cutoff )
8903  return SCIP_OKAY;
8904  (*separated) = TRUE;
8905  }
8906 
8907  minfeasibility = SCIPinfinity(scip);
8908  row = NULL;
8909 
8910  /* check each row of small covers that is not contained in LP */
8911  for( r = 0; r < consdata->nbcoverrows; ++r )
8912  {
8913  if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8914  {
8915  SCIP_Real feasibility;
8916 
8917  assert(consdata->bcoverrows[r] != NULL);
8918  if( sol != NULL )
8919  feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8920  else
8921  feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8922 
8923  if( minfeasibility > feasibility )
8924  {
8925  minfeasibility = feasibility;
8926  row = consdata->bcoverrows[r];
8927  }
8928  }
8929  }
8930 
8931  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8932 
8933  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8934  {
8935  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8936  SCIPconsGetName(cons), minfeasibility);
8937 
8938  assert(row != NULL);
8939  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8940  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8941  if ( *cutoff )
8942  return SCIP_OKAY;
8943  (*separated) = TRUE;
8944  }
8945 
8946  return SCIP_OKAY;
8947 }
8948 
8949 /** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
8950 static
8952  SCIP* scip, /**< SCIP data structure */
8953  SCIP_CONS* cons, /**< constraint to be checked */
8954  int* startindices, /**< permutation with rspect to the start times */
8955  int curtime, /**< current point in time */
8956  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8957  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8958  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
8959  SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
8960  )
8961 {
8962  SCIP_CONSDATA* consdata;
8963  char name[SCIP_MAXSTRLEN];
8964  int lhs; /* left hand side of constraint */
8965 
8966  SCIP_VAR** activevars;
8967  SCIP_ROW* row;
8968 
8969  int v;
8970 
8971  assert(nstarted > nfinished);
8972 
8973  consdata = SCIPconsGetData(cons);
8974  assert(consdata != NULL);
8975  assert(consdata->nvars > 0);
8976 
8977  SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
8978 
8979  SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
8980 
8981  if( lower )
8982  {
8983  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
8984 
8985  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, (SCIP_Real) lhs, SCIPinfinity(scip),
8986  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8987  }
8988  else
8989  {
8990  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
8991  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real) lhs,
8992  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8993  }
8994 
8995  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8996 
8997  for( v = 0; v < nstarted - nfinished; ++v )
8998  {
8999  SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
9000  }
9001 
9002  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
9003  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
9004 
9005  SCIP_CALL( SCIPaddRow(scip, row, TRUE, cutoff) );
9006 
9007  SCIP_CALL( SCIPreleaseRow(scip, &row) );
9008 
9009  /* free buffers */
9010  SCIPfreeBufferArrayNull(scip, &activevars);
9011 
9012  return SCIP_OKAY;
9013 }
9014 
9015 /** checks constraint for violation, and adds it as a cut if possible */
9016 static
9018  SCIP* scip, /**< SCIP data structure */
9019  SCIP_CONS* cons, /**< cumulative constraint to be separated */
9020  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
9021  SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
9022  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
9023  SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9024  )
9025 {
9026  SCIP_CONSDATA* consdata;
9027 
9028  int* starttimes; /* stores when each job is starting */
9029  int* endtimes; /* stores when each job ends */
9030  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
9031  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
9032 
9033  int nvars; /* number of activities for this constraint */
9034  int freecapacity; /* remaining capacity */
9035  int curtime; /* point in time which we are just checking */
9036  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
9037 
9038  int hmin;
9039  int hmax;
9040  int j;
9041 
9042  assert(scip != NULL);
9043  assert(cons != NULL);
9044 
9045  consdata = SCIPconsGetData(cons);
9046  assert(consdata != NULL);
9047 
9048  nvars = consdata->nvars;
9049 
9050  /* if no activities are associated with this cumulative then this constraint is redundant */
9051  if( nvars <= 1 )
9052  return SCIP_OKAY;
9053 
9054  assert(consdata->vars != NULL);
9055 
9056  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
9057  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
9058  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9059  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9060 
9061  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9062  SCIPconsGetName(cons), nvars);
9063 
9064  /* create event point arrays */
9065  createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9066 
9067  /* now nvars might be smaller than before! */
9068 
9069  endindex = 0;
9070  freecapacity = consdata->capacity;
9071  hmin = consdata->hmin;
9072  hmax = consdata->hmax;
9073 
9074  /* check each startpoint of a job whether the capacity is kept or not */
9075  for( j = 0; j < nvars && !(*cutoff); ++j )
9076  {
9077  curtime = starttimes[j];
9078 
9079  if( curtime >= hmax )
9080  break;
9081 
9082  /* remove the capacity requirements for all job which start at the curtime */
9083  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9084 
9085  /* add the capacity requirments for all job which end at the curtime */
9086  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9087 
9088  assert(freecapacity <= consdata->capacity);
9089  assert(endindex <= nvars);
9090 
9091  /* endindex - points to the next job which will finish */
9092  /* j - points to the last job that has been released */
9093 
9094  /* if free capacity is smaller than zero, then add rows to the LP */
9095  if( freecapacity < 0 && curtime >= hmin)
9096  {
9097  /* create capacity restriction row for current event point */
9098  SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower, cutoff) );
9099  *separated = TRUE;
9100  }
9101  } /*lint --e{850}*/
9102 
9103  /* free all buffer arrays */
9104  SCIPfreeBufferArray(scip, &endindices);
9105  SCIPfreeBufferArray(scip, &startindices);
9106  SCIPfreeBufferArray(scip, &endtimes);
9107  SCIPfreeBufferArray(scip, &starttimes);
9108 
9109  return SCIP_OKAY;
9110 }
9111 
9112 /**@} */
9113 
9114 
9115 /**@name Presolving
9116  *
9117  * @{
9118  */
9119 
9120 #ifndef NDEBUG
9121 /** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9122  * correct
9123  */
9124 static
9126  SCIP* scip, /**< SCIP data structure */
9127  SCIP_CONS* cons /**< constraint to be checked */
9128  )
9129 {
9130  SCIP_CONSDATA* consdata;
9131  int capacity;
9132  int nvars;
9133  int j;
9134 
9135  assert(scip != NULL);
9136  assert(cons != NULL);
9137 
9138  consdata = SCIPconsGetData(cons);
9139  assert(consdata != NULL);
9140 
9141  nvars = consdata->nvars;
9142 
9143  /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9144  if( nvars <= 1 )
9145  return TRUE;
9146 
9147  assert(consdata->vars != NULL);
9148  capacity = consdata->capacity;
9149 
9150  /* check each activity: if demand is larger than capacity the problem is infeasible */
9151  for ( j = 0; j < nvars; ++j )
9152  {
9153  if( consdata->demands[j] > capacity )
9154  return FALSE;
9155  }
9156 
9157  return TRUE;
9158 }
9159 #endif
9160 
9161 /** delete constraint if it consists of at most one job
9162  *
9163  * @todo this method needs to be adjusted w.r.t. effective horizon
9164  */
9165 static
9167  SCIP* scip, /**< SCIP data structure */
9168  SCIP_CONS* cons, /**< constraint to propagate */
9169  int* ndelconss, /**< pointer to store the number of deleted constraints */
9170  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9171  )
9172 {
9173  SCIP_CONSDATA* consdata;
9174 
9175  assert(scip != NULL);
9176  assert(cons != NULL);
9177 
9178  consdata = SCIPconsGetData(cons);
9179  assert(consdata != NULL);
9180 
9181  if( consdata->nvars == 0 )
9182  {
9183  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9184 
9185  SCIP_CALL( SCIPdelCons(scip, cons) );
9186  (*ndelconss)++;
9187  }
9188  else if( consdata->nvars == 1 )
9189  {
9190  if( consdata->demands[0] > consdata->capacity )
9191  (*cutoff) = TRUE;
9192  else
9193  {
9194  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9195 
9196  SCIP_CALL( SCIPdelCons(scip, cons) );
9197  (*ndelconss)++;
9198  }
9199  }
9200 
9201  return SCIP_OKAY;
9202 }
9203 
9204 /** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9205  * this is done in the SCIP_DECL_CONSINITPRE() callback
9206  */
9207 static
9209  SCIP* scip, /**< SCIP data structure */
9210  SCIP_CONS* cons /**< constraint to propagate */
9211  )
9212 {
9213  SCIP_CONSDATA* consdata;
9214  SCIP_VAR* var;
9215  int demand;
9216  int duration;
9217  int hmin;
9218  int hmax;
9219  int est;
9220  int lct;
9221  int j;
9222 
9223  assert(scip != NULL);
9224  assert(cons != NULL);
9225 
9226  consdata = SCIPconsGetData(cons);
9227  assert(consdata != NULL);
9228 
9229  hmin = consdata->hmin;
9230  hmax = consdata->hmax;
9231 
9232  SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9233  SCIPconsGetName(cons), hmin, hmax);
9234 
9235  for( j = consdata->nvars-1; j >= 0; --j )
9236  {
9237  var = consdata->vars[j];
9238  demand = consdata->demands[j];
9239  duration = consdata->durations[j];
9240 
9241  /* earliest completion time (ect) and latest start time (lst) */
9242  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9243  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9244 
9245  if( demand == 0 || duration == 0 )
9246  {
9247  /* jobs with zero demand or zero duration can be removed */
9248  SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
9249  SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9250 
9251  /* remove variable form constraint */
9252  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9253  }
9254  else if( est >= hmax || lct <= hmin )
9255  {
9256  SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
9257  SCIPvarGetName(var), est, lct - duration, duration);
9258 
9259  /* delete variable at the given position */
9260  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9261 
9262  /* for the statistic we count the number of jobs which are irrelevant */
9263  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9264  }
9265  }
9266 
9267  return SCIP_OKAY;
9268 }
9269 
9270 /** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9271 static
9273  SCIP* scip, /**< SCIP data structure */
9274  SCIP_CONSDATA* consdata, /**< constraint data */
9275  int pos, /**< position of job in the consdata */
9276  int* nchgbds, /**< pointer to store the number of changed bounds */
9277  int* naddconss, /**< pointer to store the number of added constraints */
9278  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9279  )
9280 {
9281  SCIP_VAR* var;
9282  SCIP_Bool tightened;
9283  int duration;
9284  int ect;
9285  int lst;
9286 
9287  assert(scip != NULL);
9288 
9289  /* zero energy jobs should be removed already */
9290  assert(consdata->durations[pos] > 0);
9291  assert(consdata->demands[pos] > 0);
9292 
9293  var = consdata->vars[pos];
9294  assert(var != NULL);
9295  duration = consdata->durations[pos];
9296 
9297  /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9298  SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9299  SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9300 
9301  /* earliest completion time (ect) and latest start time (lst) */
9302  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9303  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9304 
9305  /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9306  if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9307  return SCIP_OKAY;
9308 
9309  if( ect > consdata->hmin && lst < consdata->hmax )
9310  {
9311  /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9312  *cutoff = TRUE;
9313  }
9314  else if( lst < consdata->hmax )
9315  {
9316  /* move the latest start time of this job in such a way that it finishes before or at hmin */
9317  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9318  assert(tightened);
9319  assert(!(*cutoff));
9320  (*nchgbds)++;
9321  }
9322  else if( ect > consdata->hmin )
9323  {
9324  /* move the earliest start time of this job in such a way that it starts after or at hmax */
9325  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9326  assert(tightened);
9327  assert(!(*cutoff));
9328  (*nchgbds)++;
9329  }
9330  else
9331  {
9332  /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9333  * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9334  *
9335  * (var <= hmin - duration) /\ (var >= hmax)
9336  */
9337  SCIP_CONS* cons;
9338 
9339  SCIP_VAR* vartuple[2];
9340  SCIP_BOUNDTYPE boundtypetuple[2];
9341  SCIP_Real boundtuple[2];
9342 
9343  char name[SCIP_MAXSTRLEN];
9344  int leftbound;
9345  int rightbound;
9346 
9347  leftbound = consdata->hmin - duration;
9348  rightbound = consdata->hmax;
9349 
9350  /* allocate temporary memory for arrays */
9351  vartuple[0] = var;
9352  vartuple[1] = var;
9353  boundtuple[0] = (SCIP_Real)leftbound;
9354  boundtuple[1] = (SCIP_Real)rightbound;
9355  boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9356  boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9357 
9358  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9359  SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9360 
9361  /* create and add bounddisjunction constraint */
9362  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9363  TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9364 
9365  SCIPdebugPrintCons(scip, cons, NULL);
9366 
9367  /* add and release the new constraint */
9368  SCIP_CALL( SCIPaddCons(scip, cons) );
9369  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9370  (*naddconss)++;
9371  }
9372 
9373  return SCIP_OKAY;
9374 }
9375 
9376 /** try to removed over sizeed jobs (the demand is larger than the capacity) */
9377 static
9379  SCIP* scip, /**< SCIP data structure */
9380  SCIP_CONS* cons, /**< constraint */
9381  int* nchgbds, /**< pointer to store the number of changed bounds */
9382  int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9383  int* naddconss, /**< pointer to store the number of added constraints */
9384  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9385  )
9386 {
9387  SCIP_CONSDATA* consdata;
9388  int capacity;
9389  int j;
9390 
9391  consdata = SCIPconsGetData(cons);
9392  assert(consdata != NULL);
9393 
9394  /* if a cutoff was already detected just return */
9395  if( *cutoff )
9396  return SCIP_OKAY;
9397 
9398  capacity = consdata->capacity;
9399 
9400  for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9401  {
9402  if( consdata->demands[j] > capacity )
9403  {
9404  SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9405 
9406  /* remove variable form constraint */
9407  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9408  (*nchgcoefs)++;
9409  }
9410  }
9411 
9412  SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9413 
9414  return SCIP_OKAY;
9415 }
9416 
9417 /** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9418 static
9420  SCIP* scip, /**< SCIP data structure */
9421  SCIP_VAR* var, /**< integer variable to fix */
9422  SCIP_Bool uplock, /**< has thet start time variable a up lock */
9423  int* nfixedvars /**< pointer to store the number fixed variables */
9424  )
9425 {
9426  SCIP_Bool infeasible;
9427  SCIP_Bool tightened;
9428  SCIP_Bool roundable;
9429 
9430  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9431  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9432  */
9433  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9434  return SCIP_OKAY;
9435 
9436  /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9437  * handler is the only one locking that variable up
9438  */
9439  assert(uplock == TRUE || uplock == FALSE);
9440  assert((int)TRUE == 1);
9441  assert((int)FALSE == 0);
9442 
9443  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)(uplock) )
9444  return SCIP_OKAY;
9445 
9446  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9447 
9448  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9449  * (the transformed problem is always a minimization problem)
9450  */
9451  if( !roundable )
9452  return SCIP_OKAY;
9453 
9454  SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9456 
9457  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9458  assert(!infeasible);
9459 
9460  if( tightened )
9461  {
9462  SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9463  (*nfixedvars)++;
9464  }
9465 
9466  return SCIP_OKAY;
9467 }
9468 
9469 /** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9470 static
9472  SCIP* scip, /**< SCIP data structure */
9473  SCIP_VAR* var, /**< integer variable to fix */
9474  SCIP_Bool downlock, /**< has the variable a down lock */
9475  int* nfixedvars /**< pointer to store the number fixed variables */
9476  )
9477 {
9478  SCIP_Bool infeasible;
9479  SCIP_Bool tightened;
9480  SCIP_Bool roundable;
9481 
9482  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9483  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9484  */
9485  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9486  return SCIP_OKAY;
9487 
9488  /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9489  * handler is the only one locking that variable down
9490  */
9491  assert(downlock == TRUE || downlock == FALSE);
9492  assert((int)TRUE == 1);
9493  assert((int)FALSE == 0);
9494 
9495  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)(downlock) )
9496  return SCIP_OKAY;
9497 
9498  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9499 
9500  /* is it possible, to round variable down w.r.t. objective function? */
9501  if( !roundable )
9502  return SCIP_OKAY;
9503 
9504  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9505  assert(!infeasible);
9506 
9507  if( tightened )
9508  {
9509  SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9510  (*nfixedvars)++;
9511  }
9512 
9513  return SCIP_OKAY;
9514 }
9515 
9516 /** normalize cumulative condition */
9517 static
9519  SCIP* scip, /**< SCIP data structure */
9520  int nvars, /**< number of start time variables (activities) */
9521  SCIP_VAR** vars, /**< array of start time variables */
9522  int* durations, /**< array of durations */
9523  int* demands, /**< array of demands */
9524  int* capacity, /**< pointer to store the changed cumulative capacity */
9525  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9526  int* nchgsides /**< pointer to count number of side changes */
9527  )
9528 { /*lint --e{715}*/
9529  SCIP_Longint gcd;
9530  int mindemand1;
9531  int mindemand2;
9532  int v;
9533 
9534  if( *capacity == 1 || nvars <= 1 )
9535  return SCIP_OKAY;
9536 
9537  assert(demands[nvars-1] <= *capacity);
9538  assert(demands[nvars-2] <= *capacity);
9539 
9540  gcd = (SCIP_Longint)demands[nvars-1];
9541  mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9542  mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9543 
9544  for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9545  {
9546  assert(mindemand1 <= mindemand2);
9547  assert(demands[v] <= *capacity);
9548 
9549  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9550 
9551  if( mindemand1 > demands[v] )
9552  {
9553  mindemand2 = mindemand1;
9554  mindemand1 = demands[v];
9555  }
9556  else if( mindemand2 > demands[v] )
9557  mindemand2 = demands[v];
9558  }
9559 
9560  if( mindemand1 + mindemand2 > *capacity )
9561  {
9562  SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9563 
9564  for( v = 0; v < nvars; ++v )
9565  demands[v] = 1;
9566 
9567  (*capacity) = 1;
9568 
9569  (*nchgcoefs) += nvars;
9570  (*nchgsides)++;
9571  }
9572  else if( gcd >= 2 )
9573  {
9574  SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9575 
9576  for( v = 0; v < nvars; ++v )
9577  demands[v] /= gcd;
9578 
9579  (*capacity) /= gcd;
9580 
9581  (*nchgcoefs) += nvars;
9582  (*nchgsides)++;
9583  }
9584 
9585  return SCIP_OKAY;
9586 }
9587 
9588 /** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9589  * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9590  * capacity since in that case none of the jobs can run in parallel
9591  */
9592 static
9594  SCIP* scip, /**< SCIP data structure */
9595  SCIP_CONS* cons, /**< cumulative constraint */
9596  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9597  int* nchgsides /**< pointer to count number of side changes */
9598  )
9599 {
9600  SCIP_CONSDATA* consdata;
9601  int capacity;
9602 
9603  assert(nchgcoefs != NULL);
9604  assert(nchgsides != NULL);
9605  assert(!SCIPconsIsModifiable(cons));
9606 
9607  consdata = SCIPconsGetData(cons);
9608  assert(consdata != NULL);
9609 
9610  if( consdata->normalized )
9611  return SCIP_OKAY;
9612 
9613  capacity = consdata->capacity;
9614 
9615  /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9616 
9617  SCIP_CALL( normalizeCumulativeCondition(scip, consdata->nvars, consdata->vars, consdata->durations,
9618  consdata->demands, &consdata->capacity, nchgcoefs, nchgsides) );
9619 
9620  consdata->normalized = TRUE;
9621 
9622  if( capacity > consdata->capacity )
9623  consdata->varbounds = FALSE;
9624 
9625  return SCIP_OKAY;
9626 }
9627 
9628 /** computes for the given cumulative condition the effective horizon */
9629 static
9631  SCIP* scip, /**< SCIP data structure */
9632  int nvars, /**< number of variables (jobs) */
9633  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9634  int* durations, /**< array containing corresponding durations */
9635  int* demands, /**< array containing corresponding demands */
9636  int capacity, /**< available cumulative capacity */
9637  int* hmin, /**< pointer to store the left bound of the effective horizon */
9638  int* hmax, /**< pointer to store the right bound of the effective horizon */
9639  int* split /**< point were the cumulative condition can be split */
9640  )
9641 {
9642  SCIP_PROFILE* profile;
9643 
9644  /* create empty resource profile with infinity resource capacity */
9645  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9646 
9647  /* create worst case resource profile */
9648  SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
9649 
9650  /* print resource profile in if SCIP_DEBUG is defined */
9651  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
9652 
9653  /* computes the first time point where the resource capacity can be violated */
9654  (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9655 
9656  /* computes the first time point where the resource capacity is satisfied for sure */
9657  (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9658 
9659  (*split) = (*hmax);
9660 
9661  if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9662  {
9663  int* timepoints;
9664  int* loads;
9665  int ntimepoints;
9666  int t;
9667 
9668  /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9669  * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9670  * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9671  * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9672  * explain the certain "old" bound changes
9673  */
9674 
9675  /* search for time points */
9676  ntimepoints = SCIPprofileGetNTimepoints(profile);
9677  timepoints = SCIPprofileGetTimepoints(profile);
9678  loads = SCIPprofileGetLoads(profile);
9679 
9680  /* 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 */
9681  for( t = 0; t < ntimepoints; ++t )
9682  {
9683  /* ignore all time points before the effective horizon */
9684  if( timepoints[t] <= *hmin )
9685  continue;
9686 
9687  /* ignore all time points after the effective horizon */
9688  if( timepoints[t] >= *hmax )
9689  break;
9690 
9691  /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9692  * can split the cumulative constraint into two cumulative constraints
9693  */
9694  if( loads[t] <= capacity )
9695  {
9696  (*split) = timepoints[t];
9697  break;
9698  }
9699  }
9700  }
9701 
9702  /* free worst case profile */
9703  SCIPprofileFree(&profile);
9704 
9705  return SCIP_OKAY;
9706 }
9707 
9708 /** creates and adds a cumulative constraint */
9709 static
9711  SCIP* scip, /**< SCIP data structure */
9712  const char* name, /**< name of constraint */
9713  int nvars, /**< number of variables (jobs) */
9714  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9715  int* durations, /**< array containing corresponding durations */
9716  int* demands, /**< array containing corresponding demands */
9717  int capacity, /**< available cumulative capacity */
9718  int hmin, /**< left bound of time axis to be considered (including hmin) */
9719  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9720  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9721  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9722  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9723  * Usually set to TRUE. */
9724  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9725  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9726  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9727  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9728  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9729  * Usually set to TRUE. */
9730  SCIP_Bool local, /**< is constraint only valid locally?
9731  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9732  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9733  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9734  * adds coefficients to this constraint. */
9735  SCIP_Bool dynamic, /**< is constraint subject to aging?
9736  * Usually set to FALSE. Set to TRUE for own cuts which
9737  * are seperated as constraints. */
9738  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9739  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9740  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9741  * if it may be moved to a more global node?
9742  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9743  )
9744 {
9745  SCIP_CONS* cons;
9746 
9747  /* creates cumulative constraint and adds it to problem */
9748  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9749  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9750 
9751  /* adjust the effective time horizon of the new constraint */
9752  SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9753  SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9754 
9755  /* add and release new cumulative constraint */
9756  SCIP_CALL( SCIPaddCons(scip, cons) );
9757  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9758 
9759  return SCIP_OKAY;
9760 }
9761 
9762 /** computes the effective horizon and checks if the constraint can be decompsed */
9763 static
9765  SCIP* scip, /**< SCIP data structure */
9766  SCIP_CONS* cons, /**< cumulative constraint */
9767  int* ndelconss, /**< pointer to store the number of deleted constraints */
9768  int* naddconss, /**< pointer to store the number of added constraints */
9769  int* nchgsides /**< pointer to store the number of changed sides */
9770  )
9771 {
9772  SCIP_CONSDATA* consdata;
9773  int hmin;
9774  int hmax;
9775  int split;
9776 
9777  consdata = SCIPconsGetData(cons);
9778  assert(consdata != NULL);
9779 
9780  if( consdata->nvars <= 1 )
9781  return SCIP_OKAY;
9782 
9783  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9784  consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9785 
9786  /* check if this time point improves the effective horizon */
9787  if( consdata->hmin < hmin )
9788  {
9789  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9790 
9791  consdata->hmin = hmin;
9792  (*nchgsides)++;
9793  }
9794 
9795  /* check if this time point improves the effective horizon */
9796  if( consdata->hmax > hmax )
9797  {
9798  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9799  consdata->hmax = hmax;
9800  (*nchgsides)++;
9801  }
9802 
9803  /* check if the constraint is redundant */
9804  if( consdata->hmax <= consdata->hmin )
9805  {
9806  SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9807  SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9808 
9809  SCIP_CALL( SCIPdelCons(scip, cons) );
9810  (*ndelconss)++;
9811  }
9812  else if( consdata->hmin < split && split < consdata->hmax )
9813  {
9814  char name[SCIP_MAXSTRLEN];
9815  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9816 
9817  SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9818  SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9819 
9820  assert(split < consdata->hmax);
9821 
9822  /* creates cumulative constraint and adds it to problem */
9823  SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9824  consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9827 
9828  /* adjust the effective time horizon of the constraint */
9829  consdata->hmax = split;
9830 
9831  assert(consdata->hmin < consdata->hmax);
9832 
9833  /* for the statistic we count the number of time we decompose a cumulative constraint */
9835  (*naddconss)++;
9836  }
9837 
9838  return SCIP_OKAY;
9839 }
9840 
9841 
9842 /** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9843  *
9844  * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9845  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9846  *
9847  * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9848  * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9849  * down-lock of the corresponding start time variable can be removed.
9850  *
9851  * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9852  * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9853  * negative, than the job can be dual fixed to its earlier start time (est).
9854  *
9855  * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9856  * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9857  * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9858  *
9859  * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9860  * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9861  * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9862  * form variable domain is dual feasible.
9863  *
9864  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9865  * the cumulative condition; The deletion has to be done later.
9866  */
9867 static
9869  SCIP* scip, /**< SCIP data structure */
9870  int nvars, /**< number of start time variables (activities) */
9871  SCIP_VAR** vars, /**< array of start time variables */
9872  int* durations, /**< array of durations */
9873  int hmin, /**< left bound of time axis to be considered (including hmin) */
9874  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9875  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9876  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9877  SCIP_CONS* cons, /**< underlying constraint, or NULL */
9878  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9879  int* nfixedvars, /**< pointer to store the number of fixed variables */
9880  int* nchgsides, /**< pointer to store the number of changed sides */
9881  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9882  )
9883 {
9884  SCIP_Real* downimpllbs;
9885  SCIP_Real* downimplubs;
9886  SCIP_Real* downproplbs;
9887  SCIP_Real* downpropubs;
9888  SCIP_Real* upimpllbs;
9889  SCIP_Real* upimplubs;
9890  SCIP_Real* upproplbs;
9891  SCIP_Real* uppropubs;
9892 
9893  int firstminect;
9894  int secondminect;
9895  int v;
9896 
9897  /* get temporary memory for storing probing results needed for step (4) and (5) */
9898  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9899  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9900  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9901  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9902  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9903  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9904  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9905  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9906 
9907  assert(scip != NULL);
9908  assert(nvars > 1);
9909  assert(cons != NULL);
9910 
9911  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9912 
9913  firstminect = INT_MAX;
9914  secondminect = INT_MAX;
9915 
9916  /* compute the two smallest earlier completion times; which are needed for step (5) */
9917  for( v = 0; v < nvars; ++v )
9918  {
9919  int ect;
9920 
9921  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9922 
9923  if( ect < firstminect )
9924  {
9925  secondminect = firstminect;
9926  firstminect = ect;
9927  }
9928  else if( ect < secondminect )
9929  secondminect = ect;
9930  }
9931 
9932  /* loop over all jobs and check if one of the 5 reductions can be applied */
9933  for( v = 0; v < nvars; ++v )
9934  {
9935  SCIP_VAR* var;
9936  int duration;
9937 
9938  int alternativelb;
9939  int minect;
9940  int est;
9941  int ect;
9942  int lst;
9943  int lct;
9944 
9945  var = vars[v];
9946  assert(var != NULL);
9947 
9948  duration = durations[v];
9949  assert(duration > 0);
9950 
9951  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
9952  * time (lct)
9953  */
9954  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9955  ect = est + duration;
9956  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9957  lct = lst + duration;
9958 
9959  /* compute the earliest completion time of all remaining jobs */
9960  if( ect == firstminect )
9961  minect = secondminect;
9962  else
9963  minect = firstminect;
9964 
9965  /* compute potential alternative lower bound (step (4) and (5)) */
9966  alternativelb = MAX(hmin+1, minect);
9967  alternativelb = MIN(alternativelb, hmax);
9968 
9969  if( lct <= hmin )
9970  {
9971  /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
9972  * cumulative condition
9973  */
9974  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
9975  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
9976 
9977  /* mark variable to be irrelevant */
9978  irrelevants[v] = TRUE;
9979 
9980  /* for the statistic we count the number of jobs which are irrelevant */
9981  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9982  }
9983  else if( lst <= hmin && SCIPconsIsChecked(cons) )
9984  {
9985  /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
9986  * so the down lock can be omitted
9987  */
9988 
9989  assert(downlocks != NULL);
9990  assert(uplocks != NULL);
9991 
9992  if( !uplocks[v] )
9993  {
9994  /* the variables has no up lock and we can also remove the down lock;
9995  * => lst <= hmin and ect >= hmax
9996  * => remove job and reduce capacity by the demand of that job
9997  *
9998  * We mark the job to be deletable. The removement together with the capacity reducion is done later
9999  */
10000 
10001  SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
10002  SCIPvarGetName(var), ect - duration, lst, duration);
10003 
10004  /* mark variable to be irrelevant */
10005  irrelevants[v] = TRUE;
10006 
10007  /* for the statistic we count the number of jobs which always run during the effective horizon */
10009  }
10010 
10011  if( downlocks[v] )
10012  {
10013  SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
10014  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10015 
10016  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
10017  downlocks[v] = FALSE;
10018  (*nchgsides)++;
10019 
10020  /* for the statistic we count the number of removed locks */
10022  }
10023  }
10024  else if( ect <= hmin )
10025  {
10026  /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
10027  * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
10028  * removed form the cumulative condition after it was fixed to its earliest start time
10029  */
10030 
10031  /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
10032  * bound;
10033  */
10034  if( downlocks != NULL && SCIPconsIsChecked(cons) )
10035  {
10036  /* fix integer start time variable if possible to it lower bound */
10037  SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
10038  }
10039 
10040  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10041  {
10042  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
10043  SCIPvarGetName(var), ect - duration, lst, duration);
10044 
10045  /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
10046  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
10047 
10048  /* mark variable to be irrelevant */
10049  irrelevants[v] = TRUE;
10050 
10051  /* for the statistic we count the number of jobs which are dual fixed */
10053  }
10054  }
10055  else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10056  {
10057  assert(downlocks != NULL);
10058 
10059  /* check step (4) and (5) */
10060 
10061  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10062  * is in favor of rounding the variable down
10063  */
10064  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
10065  {
10066  SCIP_Bool roundable;
10067 
10068  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10069 
10070  if( roundable )
10071  {
10072  if( alternativelb > lst )
10073  {
10074  SCIP_Bool infeasible;
10075  SCIP_Bool fixed;
10076 
10077  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10078  assert(!infeasible);
10079  assert(fixed);
10080 
10081  (*nfixedvars)++;
10082 
10083  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10084  * constraints
10085  */
10087  }
10088  else
10089  {
10090  SCIP_Bool success;
10091 
10092  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10093  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10094  * infeasible we can apply the dual reduction; otherwise we do nothing
10095  */
10096  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10097  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10098  nfixedvars, &success, cutoff) );
10099 
10100  if( success )
10101  {
10103  }
10104  }
10105  }
10106  }
10107  }
10108 
10109  SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10110  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10111  }
10112 
10113  /* free temporary memory */
10114  SCIPfreeBufferArray(scip, &uppropubs);
10115  SCIPfreeBufferArray(scip, &upproplbs);
10116  SCIPfreeBufferArray(scip, &upimplubs);
10117  SCIPfreeBufferArray(scip, &upimpllbs);
10118  SCIPfreeBufferArray(scip, &downpropubs);
10119  SCIPfreeBufferArray(scip, &downproplbs);
10120  SCIPfreeBufferArray(scip, &downimplubs);
10121  SCIPfreeBufferArray(scip, &downimpllbs);
10122 
10123  return SCIP_OKAY;
10124 }
10125 
10126 /** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10127  *
10128  * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10129  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10130  *
10131  * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10132  * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10133  * up-lock of the corresponding start time variable can be removed.
10134  *
10135  * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10136  * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10137  * positive, than the job can be dual fixed to its latest start time (lst).
10138  *
10139  * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10140  * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10141  * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10142  * of the corresponding job).
10143 
10144  * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10145  * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10146  * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10147  * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10148  *
10149  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10150  * the cumulative condition; The deletion has to be done later.
10151  */
10152 static
10154  SCIP* scip, /**< SCIP data structure */
10155  int nvars, /**< number of start time variables (activities) */
10156  SCIP_VAR** vars, /**< array of start time variables */
10157  int* durations, /**< array of durations */
10158  int hmin, /**< left bound of time axis to be considered (including hmin) */
10159  int hmax, /**< right bound of time axis to be considered (not including hmax) */
10160  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10161  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10162  SCIP_CONS* cons, /**< underlying constraint, or NULL */
10163  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10164  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10165  int* nchgsides, /**< pointer to store the number of changed sides */
10166  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10167  )
10168 {
10169  SCIP_Real* downimpllbs;
10170  SCIP_Real* downimplubs;
10171  SCIP_Real* downproplbs;
10172  SCIP_Real* downpropubs;
10173  SCIP_Real* upimpllbs;
10174  SCIP_Real* upimplubs;
10175  SCIP_Real* upproplbs;
10176  SCIP_Real* uppropubs;
10177 
10178  int firstmaxlst;
10179  int secondmaxlst;
10180  int v;
10181 
10182  /* get temporary memory for storing probing results needed for step (4) and (5) */
10183  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10184  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10185  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10186  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10187  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10188  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10189  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10190  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10191 
10192  assert(scip != NULL);
10193  assert(nvars > 1);
10194  assert(cons != NULL);
10195 
10196  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10197 
10198  firstmaxlst = INT_MIN;
10199  secondmaxlst = INT_MIN;
10200 
10201  /* compute the two largest latest start times; which are needed for step (5) */
10202  for( v = 0; v < nvars; ++v )
10203  {
10204  int lst;
10205 
10206  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(vars[v]));
10207 
10208  if( lst > firstmaxlst )
10209  {
10210  secondmaxlst = firstmaxlst;
10211  firstmaxlst = lst;
10212  }
10213  else if( lst > secondmaxlst )
10214  secondmaxlst = lst;
10215  }
10216 
10217  /* loop over all jobs and check if one of the 5 reductions can be applied */
10218  for( v = 0; v < nvars; ++v )
10219  {
10220  SCIP_VAR* var;
10221  int duration;
10222 
10223  int alternativeub;
10224  int maxlst;
10225  int est;
10226  int ect;
10227  int lst;
10228 
10229  var = vars[v];
10230  assert(var != NULL);
10231 
10232  duration = durations[v];
10233  assert(duration > 0);
10234 
10235  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10236  * time (lct)
10237  */
10238  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10239  ect = est + duration;
10240  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10241 
10242  /* compute the latest start time of all remaining jobs */
10243  if( lst == firstmaxlst )
10244  maxlst = secondmaxlst;
10245  else
10246  maxlst = firstmaxlst;
10247 
10248  /* compute potential alternative upper bound (step (4) and (5)) */
10249  alternativeub = MIN(hmax - 1, maxlst) - duration;
10250  alternativeub = MAX(alternativeub, hmin);
10251 
10252  if( est >= hmax )
10253  {
10254  /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10255  * cumulative condition
10256  */
10257  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10258  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10259 
10260  /* mark variable to be irrelevant */
10261  irrelevants[v] = TRUE;
10262 
10263  /* for the statistic we count the number of jobs which are irrelevant */
10264  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10265  }
10266  else if( ect >= hmax && SCIPconsIsChecked(cons) )
10267  {
10268  assert(downlocks != NULL);
10269  assert(uplocks != NULL);
10270 
10271  /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10272  * so the up lock can be omitted
10273  */
10274 
10275  if( !downlocks[v] )
10276  {
10277  /* the variables has no down lock and we can also remove the up lock;
10278  * => lst <= hmin and ect >= hmax
10279  * => remove job and reduce capacity by the demand of that job
10280  */
10281  SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10282  SCIPvarGetName(var), est, lst, duration);
10283 
10284  /* mark variable to be irrelevant */
10285  irrelevants[v] = TRUE;
10286 
10287  /* for the statistic we count the number of jobs which always run during the effective horizon */
10289  }
10290 
10291  if( uplocks[v] )
10292  {
10293  SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10294  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10295 
10296  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10297  uplocks[v] = FALSE;
10298  (*nchgsides)++;
10299 
10300  /* for the statistic we count the number of removed locks */
10302  }
10303  }
10304  else if( lst >= hmax )
10305  {
10306  /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10307  * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10308  * removed form the cumulative condition after it was fixed to its latest start time
10309  */
10310 
10311  /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10312  * bound
10313  */
10314  if( uplocks != NULL && SCIPconsIsChecked(cons) )
10315  {
10316  /* fix integer start time variable if possible to its upper bound */
10317  SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10318  }
10319 
10320  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10321  {
10322  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10323  SCIPvarGetName(var), est, lst, duration);
10324 
10325  /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10326  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10327 
10328  /* mark variable to be irrelevant */
10329  irrelevants[v] = TRUE;
10330 
10331  /* for the statistic we count the number of jobs which are dual fixed */
10333  }
10334  }
10335  else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10336  {
10337  assert(uplocks != NULL);
10338 
10339  /* check step (4) and (5) */
10340 
10341  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10342  * is in favor of rounding the variable down
10343  */
10344  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
10345  {
10346  SCIP_Bool roundable;
10347 
10348  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10349 
10350  if( roundable )
10351  {
10352  if( alternativeub < est )
10353  {
10354  SCIP_Bool infeasible;
10355  SCIP_Bool fixed;
10356 
10357  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10358  assert(!infeasible);
10359  assert(fixed);
10360 
10361  (*nfixedvars)++;
10362 
10363  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10364  * constraints
10365  */
10367  }
10368  else
10369  {
10370  SCIP_Bool success;
10371 
10372  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10373  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10374  * in infeasible we can apply the dual reduction; otherwise we do nothing
10375  */
10376  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10377  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10378  nfixedvars, &success, cutoff) );
10379 
10380  if( success )
10381  {
10383  }
10384  }
10385  }
10386  }
10387  }
10388  }
10389 
10390  /* free temporary memory */
10391  SCIPfreeBufferArray(scip, &uppropubs);
10392  SCIPfreeBufferArray(scip, &upproplbs);
10393  SCIPfreeBufferArray(scip, &upimplubs);
10394  SCIPfreeBufferArray(scip, &upimpllbs);
10395  SCIPfreeBufferArray(scip, &downpropubs);
10396  SCIPfreeBufferArray(scip, &downproplbs);
10397  SCIPfreeBufferArray(scip, &downimplubs);
10398  SCIPfreeBufferArray(scip, &downimpllbs);
10399 
10400  return SCIP_OKAY;
10401 }
10402 
10403 /** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10404 static
10406  SCIP* scip, /**< SCIP data structure */
10407  SCIP_CONS* cons, /**< cumulative constraint */
10408  int* nfixedvars, /**< pointer to store the number of fixed variables */
10409  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10410  int* nchgsides, /**< pointer to store the number of changed sides */
10411  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10412  )
10413 {
10414  SCIP_CONSDATA* consdata;
10415  SCIP_Bool* irrelevants;
10416  int nvars;
10417  int v;
10418 
10419  assert(scip != NULL);
10420  assert(cons != NULL);
10421  assert(!(*cutoff));
10422 
10423  consdata = SCIPconsGetData(cons);
10424  assert(consdata != NULL);
10425 
10426  nvars = consdata->nvars;
10427 
10428  if( nvars <= 1 )
10429  return SCIP_OKAY;
10430 
10431  SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10432  BMSclearMemoryArray(irrelevants, nvars);
10433 
10434  /* presolve constraint form the earlier start time point of view */
10435  SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10436  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10437  irrelevants, nfixedvars, nchgsides, cutoff) );
10438 
10439  /* presolve constraint form the latest completion time point of view */
10440  SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10441  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10442  irrelevants, nfixedvars, nchgsides, cutoff) );
10443 
10444  /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10445  * order to ensure a correct behaviour
10446  */
10447  for( v = nvars-1; v >= 0; --v )
10448  {
10449  if( irrelevants[v] )
10450  {
10451  SCIP_VAR* var;
10452  int ect;
10453  int lst;
10454 
10455  var = consdata->vars[v];
10456  assert(var != NULL);
10457 
10458  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10459  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10460 
10461  /* check if the jobs runs completely during the effective horizon */
10462  if( lst <= consdata->hmin && ect >= consdata->hmax )
10463  {
10464  if( consdata->capacity < consdata->demands[v] )
10465  {
10466  *cutoff = TRUE;
10467  break;
10468  }
10469 
10470  consdata->capacity -= consdata->demands[v];
10471  consdata->varbounds = FALSE;
10472  }
10473 
10474  SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10475  (*nchgcoefs)++;
10476  }
10477  }
10478 
10479  SCIPfreeBufferArray(scip, &irrelevants);
10480 
10481  return SCIP_OKAY;
10482 }
10483 
10484 /** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10485 static
10487  SCIP* scip, /**< SCIP data structure */
10488  SCIP_CONSDATA* consdata, /**< constraint data */
10489  int* startindices, /**< permutation with rspect to the start times */
10490  int curtime, /**< current point in time */
10491  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10492  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10493  SCIP_Longint** demands, /**< pointer to array storing the demands */
10494  int* ndemands /**< pointer to store the number of different demands */
10495  )
10496 {
10497  int startindex;
10498  int ncountedvars;
10499 
10500  assert(demands != NULL);
10501  assert(ndemands != NULL);
10502 
10503  ncountedvars = 0;
10504  startindex = nstarted - 1;
10505 
10506  *ndemands = 0;
10507 
10508  /* search for the (nstarted - nfinished) jobs which are active at curtime */
10509  while( nstarted - nfinished > ncountedvars )
10510  {
10511  SCIP_VAR* var;
10512  int endtime;
10513  int varidx;
10514 
10515  /* collect job information */
10516  varidx = startindices[startindex];
10517  assert(varidx >= 0 && varidx < consdata->nvars);
10518 
10519  var = consdata->vars[varidx];
10520  assert(var != NULL);
10521 
10522  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10523 
10524  /* check the end time of this job is larger than the curtime; in this case the job is still running */
10525  if( endtime > curtime )
10526  {
10527  if( consdata->demands[varidx] < consdata->capacity )
10528  {
10529  (*demands)[*ndemands] = consdata->demands[varidx];
10530  (*ndemands)++;
10531  }
10532  ncountedvars++;
10533  }
10534 
10535  startindex--;
10536  }
10537 
10538  return SCIP_OKAY;
10539 }
10540 
10541 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10542  * constraint
10543  */
10544 static
10546  SCIP* scip, /**< SCIP data structure */
10547  SCIP_CONS* cons, /**< constraint to be checked */
10548  int* startindices, /**< permutation with rspect to the start times */
10549  int curtime, /**< current point in time */
10550  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10551  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10552  int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10553  )
10554 {
10555  SCIP_CONSDATA* consdata;
10556  SCIP_Longint* demands;
10557  SCIP_Real* profits;
10558  int* items;
10559  int ndemands;
10560  SCIP_Bool success;
10561  SCIP_Real solval;
10562  int j;
10563  assert(nstarted > nfinished);
10564 
10565  consdata = SCIPconsGetData(cons);
10566  assert(consdata != NULL);
10567  assert(consdata->nvars > 0);
10568  assert(consdata->capacity > 0);
10569 
10570  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10571  ndemands = 0;
10572 
10573  /* get demand array to initialize knapsack problem */
10574  SCIP_CALL( collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands) );
10575 
10576  /* create array for profits */
10577  SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10578  SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10579  for( j = 0; j < ndemands; ++j )
10580  {
10581  profits[j] = (SCIP_Real) demands[j];
10582  items[j] = j;/* this is only a dummy value*/
10583  }
10584 
10585  /* solve knapsack problem and get maximum capacity usage <= capacity */
10586  SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10587  items, NULL, NULL, NULL, NULL, &solval, &success) );
10588 
10589  assert(SCIPisFeasIntegral(scip, solval));
10590 
10591  /* store result */
10592  *bestcapacity = SCIPconvertRealToInt(scip, solval);
10593 
10594  SCIPfreeBufferArray(scip, &items);
10595  SCIPfreeBufferArray(scip, &profits);
10596  SCIPfreeBufferArray(scip, &demands);
10597 
10598  return SCIP_OKAY;
10599 }
10600 
10601 /** try to tighten the capacity
10602  * -- using DP for knapsack, we find the maximum possible capacity usage
10603  * -- neglects hmin and hmax, such that it is also able to check solutions globally
10604  */
10605 static
10607  SCIP* scip, /**< SCIP data structure */
10608  SCIP_CONS* cons, /**< cumulative constraint */
10609  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10610  int* nchgsides /**< pointer to store the number of changed sides */
10611  )
10612 {
10613  SCIP_CONSDATA* consdata;
10614  int* starttimes; /* stores when each job is starting */
10615  int* endtimes; /* stores when each job ends */
10616  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10617  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10618 
10619  int nvars; /* number of activities for this constraint */
10620  int freecapacity; /* remaining capacity */
10621  int curtime; /* point in time which we are just checking */
10622  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10623 
10624  int bestcapacity;
10625 
10626  int j;
10627 
10628  assert(scip != NULL);
10629  assert(cons != NULL);
10630  assert(nchgsides != NULL);
10631 
10632  consdata = SCIPconsGetData(cons);
10633  assert(consdata != NULL);
10634 
10635  nvars = consdata->nvars;
10636 
10637  /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10638  if( nvars <= 1 || consdata->capacity <= 1 )
10639  return SCIP_OKAY;
10640 
10641  assert(consdata->vars != NULL);
10642 
10643  SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10644  SCIPconsGetName(cons), consdata->capacity);
10645 
10646  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10647  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10648  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10649  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10650 
10651  /* create event point arrays */
10652  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10653  starttimes, endtimes, startindices, endindices, FALSE);
10654 
10655  bestcapacity = 1;
10656  endindex = 0;
10657  freecapacity = consdata->capacity;
10658 
10659  /* check each startpoint of a job whether the capacity is kept or not */
10660  for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10661  {
10662  curtime = starttimes[j];
10663  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10664 
10665  /* remove the capacity requirments for all job which start at the curtime */
10666  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10667 
10668  /* add the capacity requirments for all job which end at the curtime */
10669  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10670 
10671  assert(freecapacity <= consdata->capacity);
10672  assert(endindex <= nvars);
10673 
10674  /* endindex - points to the next job which will finish */
10675  /* j - points to the last job that has been released */
10676 
10677  /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10678  if( freecapacity < 0 )
10679  {
10680  int newcapacity;
10681 
10682  newcapacity = 1;
10683 
10684  /* get best possible upper bound on capacity usage */
10685  SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10686 
10687  /* update bestcapacity */
10688  bestcapacity = MAX(bestcapacity, newcapacity);
10689  SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10690  }
10691 
10692  /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10693  if( freecapacity > 0 && freecapacity != consdata->capacity )
10694  {
10695  bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10696  SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10697  }
10698 
10699  /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10700  if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10701  {
10702  /* if demands[startindices[j]] == cap then exactly that job is running */
10703  SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10704  bestcapacity = consdata->capacity;
10705  break;
10706  }
10707  } /*lint --e{850}*/
10708 
10709  /* free all buffer arrays */
10710  SCIPfreeBufferArray(scip, &endindices);
10711  SCIPfreeBufferArray(scip, &startindices);
10712  SCIPfreeBufferArray(scip, &endtimes);
10713  SCIPfreeBufferArray(scip, &starttimes);
10714 
10715  /* check whether capacity can be tightened and whether demands need to be adjusted */
10716  if( bestcapacity < consdata->capacity )
10717  {
10718  /* cppcheck-suppress unassignedVariable */
10719  int oldnchgcoefs;
10720 
10721  SCIPdebug(oldnchgcoefs = *nchgcoefs; )
10722 
10723  SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10724  SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10725 
10726  for( j = 0; j < nvars; ++j )
10727  {
10728  if( consdata->demands[j] == consdata->capacity )
10729  {
10730  consdata->demands[j] = bestcapacity;
10731  (*nchgcoefs)++;
10732  }
10733  }
10734 
10735  consdata->capacity = bestcapacity;
10736  (*nchgsides)++;
10737 
10738  SCIPdebugMsgPrint(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs);
10739 
10740  consdata->varbounds = FALSE;
10741  }
10742 
10743  return SCIP_OKAY;
10744 }
10745 
10746 /** tries to change coefficients:
10747  * demand_j < cap && all other parallel jobs in conflict
10748  * ==> set demand_j := cap
10749  */
10750 static
10752  SCIP* scip, /**< SCIP data structure */
10753  SCIP_CONS* cons, /**< cumulative constraint */
10754  int* nchgcoefs /**< pointer to count total number of changed coefficients */
10755  )
10756 {
10757  SCIP_CONSDATA* consdata;
10758  int nvars;
10759  int j;
10760  int oldnchgcoefs;
10761  int mindemand;
10762 
10763  assert(scip != NULL);
10764  assert(cons != NULL);
10765  assert(nchgcoefs != NULL);
10766 
10767  /* get constraint data for some parameter testings only! */
10768  consdata = SCIPconsGetData(cons);
10769  assert(consdata != NULL);
10770 
10771  nvars = consdata->nvars;
10772  oldnchgcoefs = *nchgcoefs;
10773 
10774  if( nvars <= 0 )
10775  return SCIP_OKAY;
10776 
10777  /* PRE1:
10778  * check all jobs j whether: r_j + r_min > capacity holds
10779  * if so: adjust r_j to capacity
10780  */
10781  mindemand = consdata->demands[0];
10782  for( j = 0; j < nvars; ++j )
10783  {
10784  mindemand = MIN(mindemand, consdata->demands[j]);
10785  }
10786 
10787  /*check each job */
10788  for( j = 0; j < nvars; ++j )
10789  {
10790  if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10791  {
10792  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10793  consdata->demands[j], consdata->capacity);
10794  consdata->demands[j] = consdata->capacity;
10795  (*nchgcoefs)++;
10796  }
10797  }
10798 
10799  /* PRE2:
10800  * check for each job (with d_j < cap)
10801  * whether it is disjunctive to all others over the time horizon
10802  */
10803  for( j = 0; j < nvars; ++j )
10804  {
10805  SCIP_Bool chgcoef;
10806  int est_j;
10807  int lct_j;
10808  int i;
10809 
10810  assert(consdata->demands[j] <= consdata->capacity);
10811 
10812  if( consdata->demands[j] == consdata->capacity )
10813  continue;
10814 
10815  chgcoef = TRUE;
10816 
10817  est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10818  lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10819 
10820  for( i = 0; i < nvars; ++i )
10821  {
10822  int est_i;
10823  int lct_i;
10824 
10825  if( i == j )
10826  continue;
10827 
10828  est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10829  lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10830 
10831  if( est_i >= lct_j || est_j >= lct_i )
10832  continue;
10833 
10834  if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10835  {
10836  chgcoef = FALSE;
10837  break;
10838  }
10839  }
10840 
10841  if( chgcoef )
10842  {
10843  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10844  consdata->demands[j], consdata->capacity);
10845  consdata->demands[j] = consdata->capacity;
10846  (*nchgcoefs)++;
10847  }
10848  }
10849 
10850  if( (*nchgcoefs) > oldnchgcoefs )
10851  {
10852  SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10853  (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10854  }
10855 
10856  return SCIP_OKAY;
10857 }
10858 
10859 #if 0
10860 /** try to reformulate constraint by replacing certain jobs */
10861 static
10862 SCIP_RETCODE reformulateCons(
10863  SCIP* scip, /**< SCIP data structure */
10864  SCIP_CONS* cons, /**< cumulative constraint */
10865  int* naggrvars /**< pointer to store the number of aggregated variables */
10866  )
10867 {
10868  SCIP_CONSDATA* consdata;
10869  int hmin;
10870  int hmax;
10871  int nvars;
10872  int v;
10873 
10874  consdata = SCIPconsGetData(cons);
10875  assert(cons != NULL);
10876 
10877  nvars = consdata->nvars;
10878  assert(nvars > 1);
10879 
10880  hmin = consdata->hmin;
10881  hmax = consdata->hmax;
10882  assert(hmin < hmax);
10883 
10884  for( v = 0; v < nvars; ++v )
10885  {
10886  SCIP_VAR* var;
10887  int duration;
10888  int est;
10889  int ect;
10890  int lst;
10891  int lct;
10892 
10893  var = consdata->vars[v];
10894  assert(var != NULL);
10895 
10896  duration = consdata->durations[v];
10897 
10898  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10899  ect = est + duration;
10900  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10901  lct = lst + duration;
10902 
10903  /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10904  assert(lst > hmin || ect < hmax);
10905 
10906  if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10907  {
10908  SCIP_VAR* aggrvar;
10909  char name[SCIP_MAXSTRLEN];
10910  SCIP_Bool infeasible;
10911  SCIP_Bool redundant;
10912  SCIP_Bool aggregated;
10913  int shift;
10914 
10915  shift = est - (hmin - lct + MIN(hmin, ect));
10916  assert(shift > 0);
10917  lst = hmin;
10918  duration = hmin - lct;
10919 
10920  SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10921  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10922 
10923  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10924  SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10926  SCIP_CALL( SCIPaddVar(scip, var) );
10927  SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10928 
10929  assert(!infeasible);
10930  assert(!redundant);
10931  assert(aggregated);
10932 
10933  /* replace variable */
10934  consdata->durations[v] = duration;
10935  consdata->vars[v] = aggrvar;
10936 
10937  /* remove and add locks */
10938  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10939  SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10940 
10941  SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10942 
10943  (*naggrvars)++;
10944  }
10945  }
10946 
10947  return SCIP_OKAY;
10948 }
10949 #endif
10950 
10951 /** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10952 static
10954  SCIP* scip, /**< SCIP data structure */
10955  SCIP_CONS* cons, /**< cumulative constraint */
10956  int* naddconss /**< pointer to store the number of added constraints */
10957  )
10958 {
10959  SCIP_CONSDATA* consdata;
10960  SCIP_VAR** vars;
10961  int* durations;
10962  int* demands;
10963  int capacity;
10964  int halfcapacity;
10965  int mindemand;
10966  int nvars;
10967  int v;
10968 
10969  consdata = SCIPconsGetData(cons);
10970  assert(consdata != NULL);
10971 
10972  capacity = consdata->capacity;
10973 
10974  if( capacity == 1 )
10975  return SCIP_OKAY;
10976 
10977  SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
10978  SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
10979  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10980 
10981  halfcapacity = capacity / 2;
10982  mindemand = consdata->capacity;
10983  nvars = 0;
10984 
10985  /* collect all jobs with demand larger than half of the capacity */
10986  for( v = 0; v < consdata->nvars; ++v )
10987  {
10988  if( consdata->demands[v] > halfcapacity )
10989  {
10990  vars[nvars] = consdata->vars[v];
10991  demands[nvars] = 1;
10992  durations[nvars] = consdata->durations[v];
10993  nvars++;
10994 
10995  mindemand = MIN(mindemand, consdata->demands[v]);
10996  }
10997  }
10998 
10999  if( nvars > 0 )
11000  {
11001  /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
11002  * job is still to large to be scheduled in parallel
11003  */
11004  for( v = 0; v < consdata->nvars; ++v )
11005  {
11006  if( consdata->demands[v] > halfcapacity )
11007  continue;
11008 
11009  if( mindemand + consdata->demands[v] > capacity )
11010  {
11011  demands[nvars] = 1;
11012  durations[nvars] = consdata->durations[v];
11013  vars[nvars] = consdata->vars[v];
11014  nvars++;
11015 
11016  /* @todo create one cumulative constraint and look for another small demand */
11017  break;
11018  }
11019  }
11020 
11021  /* creates cumulative constraint and adds it to problem */
11022  SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
11024  (*naddconss)++;
11025  }
11026 
11027  SCIPfreeBufferArray(scip, &demands);
11028  SCIPfreeBufferArray(scip, &durations);
11029  SCIPfreeBufferArray(scip, &vars);
11030 
11031  return SCIP_OKAY;
11032 }
11033 
11034 /** presolve given constraint */
11035 static
11037  SCIP* scip, /**< SCIP data structure */
11038  SCIP_CONS* cons, /**< cumulative constraint */
11039  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
11040  SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
11041  int* nfixedvars, /**< pointer to store the number of fixed variables */
11042 #if 0
11043  int* naggrvars, /**< pointer to counter which is increased by the number of deduced variable aggregations */
11044 #endif
11045  int* nchgbds, /**< pointer to store the number of changed bounds */
11046  int* ndelconss, /**< pointer to store the number of deleted constraints */
11047  int* naddconss, /**< pointer to store the number of added constraints */
11048  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
11049  int* nchgsides, /**< pointer to store the number of changed sides */
11050  SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
11051  SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
11052  )
11053 {
11054  assert(!SCIPconsIsDeleted(cons));
11055 
11056  /* only perform dual reductions on model constraints */
11057  if( conshdlrdata->dualpresolve && SCIPallowDualReds(scip) )
11058  {
11059  /* computes the effective horizon and checks if the constraint can be decomposed */
11060  SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11061 
11062  if( SCIPconsIsDeleted(cons) )
11063  return SCIP_OKAY;
11064 
11065  /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11066  * fixings (dual reductions)
11067  */
11068  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11069  {
11070  SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11071 
11072  if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11073  return SCIP_OKAY;
11074  }
11075 
11076  SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11077 
11078  if( *cutoff || SCIPconsIsDeleted(cons) )
11079  return SCIP_OKAY;
11080  }
11081 
11082  /* remove jobs which have a demand larger than the capacity */
11083  SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11084  assert((*cutoff) || checkDemands(scip, cons));
11085 
11086  if( *cutoff )
11087  return SCIP_OKAY;
11088 
11089  if( conshdlrdata->normalize )
11090  {
11091  /* divide demands by their greatest common divisor */
11092  SCIP_CALL( normalizeDemands(scip, cons, nchgcoefs, nchgsides) );
11093  }
11094 
11095  /* delete constraint with one job */
11096  SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11097 
11098  if( *cutoff || SCIPconsIsDeleted(cons) )
11099  return SCIP_OKAY;
11100 
11101  if( conshdlrdata->coeftightening )
11102  {
11103  /* try to tighten the capacity */
11104  SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11105 
11106  /* try to tighten the coefficients */
11107  SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11108  }
11109 
11110  assert(checkDemands(scip, cons) || *cutoff);
11111 
11112 #if 0
11113  SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11114 #endif
11115 
11116  return SCIP_OKAY;
11117 }
11118 
11119 /**@name TClique Graph callbacks
11120  *
11121  * @{
11122  */
11123 
11124 /** tclique graph data */
11125 struct TCLIQUE_Graph
11126 {
11127  SCIP_VAR** vars; /**< start time variables each of them is a node */
11128  SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11129  SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11130  SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11131  TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11132  int* ninarcs; /**< number if in arcs for the precedence graph */
11133  int* noutarcs; /**< number if out arcs for the precedence graph */
11134  int* durations; /**< for each node the duration of the corresponding job */
11135  int nnodes; /**< number of nodes */
11136  int size; /**< size of the array */
11137 };
11138 
11139 /** gets number of nodes in the graph */
11140 static
11141 TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11143  assert(tcliquegraph != NULL);
11144 
11145  return tcliquegraph->nnodes;
11146 }
11147 
11148 /** gets weight of nodes in the graph */
11149 static
11150 TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11152  assert(tcliquegraph != NULL);
11153 
11154  return tcliquegraph->weights;
11155 }
11156 
11157 /** returns, whether the edge (node1, node2) is in the graph */
11158 static
11159 TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11161  assert(tcliquegraph != NULL);
11162  assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11163  assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11164 
11165  /* check if an arc exits in the precedence graph */
11166  if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11167  return TRUE;
11168 
11169  /* check if an edge exits in the non-overlapping graph */
11170  if( tcliquegraph->demandmatrix[node1][node2] )
11171  return TRUE;
11172 
11173  return FALSE;
11174 }
11175 
11176 /** selects all nodes from a given set of nodes which are adjacent to a given node
11177  * and returns the number of selected nodes
11178  */
11179 static
11180 TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11182  int nadjnodes;
11183  int i;
11184 
11185  assert(tcliquegraph != NULL);
11186  assert(0 <= node && node < tcliquegraph->nnodes);
11187  assert(nnodes == 0 || nodes != NULL);
11188  assert(adjnodes != NULL);
11189 
11190  nadjnodes = 0;
11191 
11192  for( i = 0; i < nnodes; i++ )
11193  {
11194  /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11195  assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11196  assert(i == 0 || nodes[i-1] < nodes[i]);
11197 
11198  /* check if an edge exists */
11199  if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11200  {
11201  /* current node is adjacent to given node */
11202  adjnodes[nadjnodes] = nodes[i];
11203  nadjnodes++;
11204  }
11205  }
11206 
11207  return nadjnodes;
11208 }
11209 
11210 /** generates cuts using a clique found by algorithm for maximum weight clique
11211  * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11212  */
11213 static
11214 TCLIQUE_NEWSOL(tcliqueNewsolClique)
11215 { /*lint --e{715}*/
11216  SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11217 }
11218 
11219 /** print the tclique graph */
11220 #if 0
11221 static
11222 void tcliquePrint(
11223  SCIP* scip, /**< SCIP data structure */
11224  TCLIQUE_GRAPH* tcliquegraph /**< tclique graph */
11225  )
11226 {
11227  int nnodes;
11228  int i;
11229  int j;
11230 
11231  nnodes = tcliquegraph->nnodes;
11232 
11233  for( i = 0; i < nnodes; ++i )
11234  {
11235  for( j = 0; j < nnodes; ++j )
11236  {
11237  SCIPinfoMessage(scip, NULL, "(%d/%d) ", tcliquegraph->precedencematrix[i][j], tcliquegraph->demandmatrix[i][j]);
11238  }
11239  SCIPinfoMessage(scip, NULL, "\n");
11240  }
11241 }
11242 #endif
11243 
11244 /** @} */
11245 
11246 /** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11247  * job corresponding to variable bound variable (vlbvar)
11248  *
11249  * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11250  */
11251 static
11253  SCIP* scip, /**< SCIP data structure */
11254  SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11255  SCIP_Real vlbcoef, /**< variable bound coefficient */
11256  SCIP_Real vlbconst, /**< variable bound constant */
11257  int duration /**< duration of the variable bound variable */
11258  )
11259 {
11260  if( SCIPisEQ(scip, vlbcoef, 1.0) )
11261  {
11262  if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11263  {
11264  /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11265  return TRUE;
11266  }
11267  }
11268  else
11269  {
11270  SCIP_Real bound;
11271 
11272  bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11273 
11274  if( SCIPisLT(scip, vlbcoef, 1.0) )
11275  {
11276  SCIP_Real ub;
11277 
11278  ub = SCIPvarGetUbLocal(vlbvar);
11279 
11280  /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11281  if( SCIPisLE(scip, ub, bound) )
11282  return TRUE;
11283  }
11284  else
11285  {
11286  SCIP_Real lb;
11287 
11288  assert(SCIPisGT(scip, vlbcoef, 1.0));
11289 
11290  lb = SCIPvarGetLbLocal(vlbvar);
11291 
11292  /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11293  if( SCIPisGE(scip, lb, bound) )
11294  return TRUE;
11295  }
11296  }
11297 
11298  return FALSE;
11299 }
11300 
11301 /** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11302  * job corresponding to variable which is bounded (var)
11303  *
11304  * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11305  */
11306 static
11308  SCIP* scip, /**< SCIP data structure */
11309  SCIP_VAR* var, /**< variable which is bound from above */
11310  SCIP_Real vubcoef, /**< variable bound coefficient */
11311  SCIP_Real vubconst, /**< variable bound constant */
11312  int duration /**< duration of the variable which is bounded from above */
11313  )
11314 {
11315  SCIP_Real vlbcoef;
11316  SCIP_Real vlbconst;
11317 
11318  /* convert the variable upper bound into an variable lower bound */
11319  vlbcoef = 1.0 / vubcoef;
11320  vlbconst = -vubconst / vubcoef;
11321 
11322  return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11323 }
11324 
11325 /** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11326  * others an index larger than the number if active variables
11327  */
11328 static
11330  SCIP* scip, /**< SCIP data structure */
11331  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11332  SCIP_VAR* var, /**< variable for which we want the index */
11333  int* idx /**< pointer to store the index */
11334  )
11335 {
11336  (*idx) = SCIPvarGetProbindex(var);
11337 
11338  if( (*idx) == -1 )
11339  {
11340  if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11341  {
11342  (*idx) = SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var);
11343  }
11344  else
11345  {
11346  int pos;
11347  int v;
11348 
11349  /**@todo we might want to add the aggregation path to graph */
11350 
11351  /* check if we have to realloc memory */
11352  if( tcliquegraph->size == tcliquegraph->nnodes )
11353  {
11354  int size;
11355 
11356  size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11357  tcliquegraph->size = size;
11358 
11359  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11360  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11361  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11362  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11363  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11364 
11365  for( v = 0; v < tcliquegraph->nnodes; ++v )
11366  {
11367  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11368  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11369  }
11370  }
11371  assert(tcliquegraph->nnodes < tcliquegraph->size);
11372 
11373  pos = tcliquegraph->nnodes;
11374  assert(pos >= 0);
11375 
11376  tcliquegraph->durations[pos] = 0;
11377  tcliquegraph->weights[pos] = 0;
11378  tcliquegraph->vars[pos] = var;
11379 
11380  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11381  BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11382 
11383  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11384  BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11385 
11386  SCIP_CALL( SCIPhashmapInsertInt(tcliquegraph->varmap, (void*)var, pos) );
11387 
11388  tcliquegraph->nnodes++;
11389 
11390  for( v = 0; v < tcliquegraph->nnodes; ++v )
11391  {
11392  tcliquegraph->precedencematrix[v][pos] = 0;
11393  tcliquegraph->demandmatrix[v][pos] = 0;
11394  }
11395 
11396  (*idx) = tcliquegraph->nnodes;
11397  }
11398  }
11399  else
11400  {
11401  assert(*idx == SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var));
11402  }
11403 
11404  assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11405 
11406  return SCIP_OKAY;
11407 }
11408 
11409 /** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11410  *
11411  * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11412  * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11413  *
11414  * (i) b = 1 and c >= d
11415  * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11416  * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11417  *
11418  */
11419 static
11421  SCIP* scip, /**< SCIP data structure */
11422  TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11423  )
11424 {
11425  SCIP_VAR** vars;
11426  int nvars;
11427  int v;
11428 
11429  vars = SCIPgetVars(scip);
11430  nvars = SCIPgetNVars(scip);
11431 
11432  /* try to project each arc of the variable bound graph to precedence condition */
11433  for( v = 0; v < nvars; ++v )
11434  {
11435  SCIP_VAR** vbdvars;
11436  SCIP_VAR* var;
11437  SCIP_Real* vbdcoefs;
11438  SCIP_Real* vbdconsts;
11439  int nvbdvars;
11440  int idx1;
11441  int b;
11442 
11443  var = vars[v];
11444  assert(var != NULL);
11445 
11446  SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11447  assert(idx1 >= 0);
11448 
11449  if( tcliquegraph->durations[idx1] == 0 )
11450  continue;
11451 
11452  vbdvars = SCIPvarGetVlbVars(var);
11453  vbdcoefs = SCIPvarGetVlbCoefs(var);
11454  vbdconsts = SCIPvarGetVlbConstants(var);
11455  nvbdvars = SCIPvarGetNVlbs(var);
11456 
11457  for( b = 0; b < nvbdvars; ++b )
11458  {
11459  int idx2;
11460 
11461  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11462  assert(idx2 >= 0);
11463 
11464  if( tcliquegraph->durations[idx2] == 0 )
11465  continue;
11466 
11467  if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11468  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11469  }
11470 
11471  vbdvars = SCIPvarGetVubVars(var);
11472  vbdcoefs = SCIPvarGetVubCoefs(var);
11473  vbdconsts = SCIPvarGetVubConstants(var);
11474  nvbdvars = SCIPvarGetNVubs(var);
11475 
11476  for( b = 0; b < nvbdvars; ++b )
11477  {
11478  int idx2;
11479 
11480  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11481  assert(idx2 >= 0);
11482 
11483  if( tcliquegraph->durations[idx2] == 0 )
11484  continue;
11485 
11486  if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11487  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11488  }
11489 
11490  for( b = v+1; b < nvars; ++b )
11491  {
11492  int idx2;
11493 
11494  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11495  assert(idx2 >= 0);
11496 
11497  if( tcliquegraph->durations[idx2] == 0 )
11498  continue;
11499 
11500  /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11501  if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11502  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11503 
11504  /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11505  if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11506  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11507  }
11508  }
11509 
11510  return SCIP_OKAY;
11511 }
11512 
11513 /** compute the transitive closer of the given graph and the number of in and out arcs */
11514 static
11515 void transitiveClosure(
11516  SCIP_Bool** adjmatrix, /**< adjacent matrix */
11517  int* ninarcs, /**< array to store the number of in arcs */
11518  int* noutarcs, /**< array to store the number of out arcs */
11519  int nnodes /**< number if nodes */
11520  )
11521 {
11522  int i;
11523  int j;
11524  int k;
11525 
11526  for( i = 0; i < nnodes; ++i )
11527  {
11528  for( j = 0; j < nnodes; ++j )
11529  {
11530  if( adjmatrix[i][j] )
11531  {
11532  ninarcs[j]++;
11533  noutarcs[i]++;
11534 
11535  for( k = 0; k < nnodes; ++k )
11536  {
11537  if( adjmatrix[j][k] )
11538  adjmatrix[i][k] = TRUE;
11539  }
11540  }
11541  }
11542  }
11543 }
11544 
11545 /** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11546 static
11548  SCIP* scip, /**< SCIP data structure */
11549  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11550  SCIP_CONS** conss, /**< array of cumulative constraints */
11551  int nconss /**< number of cumulative constraints */
11552  )
11553 {
11554  int c;
11555 
11556  /* use the cumulative constraints to initialize the none overlapping graph */
11557  for( c = 0; c < nconss; ++c )
11558  {
11559  SCIP_CONSDATA* consdata;
11560  SCIP_VAR** vars;
11561  int* demands;
11562  int capacity;
11563  int nvars;
11564  int i;
11565 
11566  consdata = SCIPconsGetData(conss[c]);
11567  assert(consdata != NULL);
11568 
11569  vars = consdata->vars;
11570  demands = consdata->demands;
11571 
11572  nvars = consdata->nvars;
11573  capacity = consdata->capacity;
11574 
11575  SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11576 
11577  /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11578  for( i = 0; i < nvars; ++i )
11579  {
11580  int idx1;
11581  int j;
11582 
11583  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11584  assert(idx1 >= 0);
11585 
11586  if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11587  continue;
11588 
11589  for( j = i+1; j < nvars; ++j )
11590  {
11591  assert(consdata->durations[j] > 0);
11592 
11593  if( demands[i] + demands[j] > capacity )
11594  {
11595  int idx2;
11596  int est1;
11597  int est2;
11598  int lct1;
11599  int lct2;
11600 
11601  /* check if the effective horizon is large enough */
11602  est1 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[i]));
11603  est2 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[j]));
11604 
11605  /* at least one of the jobs needs to start at hmin or later */
11606  if( est1 < consdata->hmin && est2 < consdata->hmin )
11607  continue;
11608 
11609  lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11610  lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11611 
11612  /* at least one of the jobs needs to finish not later then hmin */
11613  if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11614  continue;
11615 
11616  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11617  assert(idx2 >= 0);
11618  assert(idx1 != idx2);
11619 
11620  if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11621  continue;
11622 
11623  SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11624 
11625  assert(tcliquegraph->durations[idx1] > 0);
11626  assert(tcliquegraph->durations[idx2] > 0);
11627 
11628  tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11629  tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11630  }
11631  }
11632  }
11633  }
11634 
11635  return SCIP_OKAY;
11636 }
11637 
11638 /** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11639  * of jobs cannot run in parallel
11640  */
11641 static
11643  SCIP* scip, /**< SCIP data structure */
11644  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11645  SCIP_CONS** conss, /**< array of cumulative constraints */
11646  int nconss /**< number of cumulative constraints */
11647  )
11648 {
11649  assert(scip != NULL);
11650  assert(tcliquegraph != NULL);
11651 
11652  /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11653  SCIP_CALL( projectVbd(scip, tcliquegraph) );
11654 
11655  /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11656  transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11657 
11658  /* constraints non-overlapping graph */
11659  SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11660 
11661  return SCIP_OKAY;
11662 }
11663 
11664 /** create cumulative constraint from conflict set */
11665 static
11667  SCIP* scip, /**< SCIP data structure */
11668  const char* name, /**< constraint name */
11669  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11670  int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11671  int ncliquenodes /**< number of nodes in the clique */
11672  )
11673 {
11674  SCIP_CONS* cons;
11675  SCIP_VAR** vars;
11676  int* durations;
11677  int* demands;
11678  int v;
11679 
11680  SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11681  SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11682  SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11683 
11684  SCIPsortInt(cliquenodes, ncliquenodes);
11685 
11686  /* collect variables, durations, and demands */
11687  for( v = 0; v < ncliquenodes; ++v )
11688  {
11689  durations[v] = tcliquegraph->durations[cliquenodes[v]];
11690  assert(durations[v] > 0);
11691  demands[v] = 1;
11692  vars[v] = tcliquegraph->vars[cliquenodes[v]];
11693  }
11694 
11695  /* create (unary) cumulative constraint */
11696  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11698 
11699  SCIP_CALL( SCIPaddCons(scip, cons) );
11700  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11701 
11702  /* free buffers */
11703  SCIPfreeBufferArray(scip, &demands);
11704  SCIPfreeBufferArray(scip, &durations);
11705  SCIPfreeBufferArray(scip, &vars);
11706 
11707  return SCIP_OKAY;
11708 }
11709 
11710 /** search for cumulative constrainst */
11711 static
11713  SCIP* scip, /**< SCIP data structure */
11714  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11715  int* naddconss /**< pointer to store the number of added constraints */
11716  )
11717 {
11718  TCLIQUE_STATUS tcliquestatus;
11719  SCIP_Bool* precedencerow;
11720  SCIP_Bool* precedencecol;
11721  SCIP_Bool* demandrow;
11722  SCIP_Bool* demandcol;
11723  SCIP_HASHTABLE* covered;
11724  int* cliquenodes;
11725  int ncliquenodes;
11726  int cliqueweight;
11727  int ntreenodes;
11728  int nnodes;
11729  int nconss;
11730  int v;
11731 
11732  nnodes = tcliquegraph->nnodes;
11733  nconss = 0;
11734 
11735  /* initialize the weight of each job with its duration */
11736  for( v = 0; v < nnodes; ++v )
11737  {
11738  tcliquegraph->weights[v] = tcliquegraph->durations[v];
11739  }
11740 
11741  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11742  SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11743  SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11744  SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11745  SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11746 
11747  /* create a hash table to store all start time variables which are already covered by at least one clique */
11748  SCIP_CALL( SCIPhashtableCreate(&covered, SCIPblkmem(scip), nnodes,
11749  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11750 
11751  /* for each variables/job we are ... */
11752  for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11753  {
11754  char name[SCIP_MAXSTRLEN];
11755  int c;
11756 
11757  /* jobs with zero durations are skipped */
11758  if( tcliquegraph->durations[v] == 0 )
11759  continue;
11760 
11761  /* check if the start time variable is already covered by at least one clique */
11762  if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11763  continue;
11764 
11765  SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11766 
11767  /* temporarily remove the connection via the precedence graph */
11768  for( c = 0; c < nnodes; ++c )
11769  {
11770  precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11771  precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11772 
11773  demandrow[c] = tcliquegraph->demandmatrix[v][c];
11774  demandcol[c] = tcliquegraph->demandmatrix[c][v];
11775 
11776 #if 0
11777  if( precedencerow[c] || precedencecol[c] )
11778  {
11779  tcliquegraph->demandmatrix[v][c] = FALSE;
11780  tcliquegraph->demandmatrix[c][v] = FALSE;
11781  }
11782 #endif
11783 
11784  tcliquegraph->precedencematrix[c][v] = FALSE;
11785  tcliquegraph->precedencematrix[v][c] = FALSE;
11786  }
11787 
11788  /* find (heuristically) maximum cliques which includes node v */
11789  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11790  tcliquegraph, tcliqueNewsolClique, NULL,
11791  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11792  10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11793 
11794  SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11795 
11796  if( ncliquenodes == 1 )
11797  continue;
11798 
11799  /* construct constraint name */
11800  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11801 
11802  SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11803  nconss++;
11804 
11805  /* all start time variable to covered hash table */
11806  for( c = 0; c < ncliquenodes; ++c )
11807  {
11808  SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11809  }
11810 
11811  /* copy the precedence relations back */
11812  for( c = 0; c < nnodes; ++c )
11813  {
11814  tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11815  tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11816 
11817  tcliquegraph->demandmatrix[v][c] = demandrow[c];
11818  tcliquegraph->demandmatrix[c][v] = demandcol[c];
11819  }
11820  }
11821 
11822  SCIPhashtableFree(&covered);
11823 
11824  SCIPfreeBufferArray(scip, &demandcol);
11825  SCIPfreeBufferArray(scip, &demandrow);
11826  SCIPfreeBufferArray(scip, &precedencecol);
11827  SCIPfreeBufferArray(scip, &precedencerow);
11828  SCIPfreeBufferArray(scip, &cliquenodes);
11829 
11830  (*naddconss) += nconss;
11831 
11832  /* for the statistic we count the number added disjunctive constraints */
11833  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11834 
11835  return SCIP_OKAY;
11836 }
11837 
11838 /** create precedence constraint (as variable bound constraint */
11839 static
11841  SCIP* scip, /**< SCIP data structure */
11842  const char* name, /**< constraint name */
11843  SCIP_VAR* var, /**< variable x that has variable bound */
11844  SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11845  int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11846  )
11847 {
11848  SCIP_CONS* cons;
11849 
11850  /* create variable bound constraint */
11851  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11853 
11854  SCIPdebugPrintCons(scip, cons, NULL);
11855 
11856  /* add constraint to problem and release it */
11857  SCIP_CALL( SCIPaddCons(scip, cons) );
11858  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11859 
11860  return SCIP_OKAY;
11861 }
11862 
11863 /** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11864 static
11866  SCIP* scip, /**< SCIP data structure */
11867  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11868  int source, /**< index of the source node */
11869  int sink, /**< index of the sink node */
11870  int* naddconss /**< pointer to store the number of added constraints */
11871  )
11872 {
11873  TCLIQUE_WEIGHT cliqueweight;
11874  TCLIQUE_STATUS tcliquestatus;
11875  SCIP_VAR** vars;
11876  int* cliquenodes;
11877  int nnodes;
11878  int lct;
11879  int est;
11880  int i;
11881 
11882  int ntreenodes;
11883  int ncliquenodes;
11884 
11885  /* check if source and sink are connencted */
11886  if( !tcliquegraph->precedencematrix[source][sink] )
11887  return SCIP_OKAY;
11888 
11889  nnodes = tcliquegraph->nnodes;
11890  vars = tcliquegraph->vars;
11891 
11892  /* reset the weights to zero */
11893  BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11894 
11895  /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11896  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11897  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[sink]));
11898 
11899  /* weight all jobs which run for sure between source and sink with their duration */
11900  for( i = 0; i < nnodes; ++i )
11901  {
11902  SCIP_VAR* var;
11903  int duration;
11904 
11905  var = vars[i];
11906  assert(var != NULL);
11907 
11908  duration = tcliquegraph->durations[i];
11909 
11910  if( i == source || i == sink )
11911  {
11912  /* source and sink are not weighted */
11913  tcliquegraph->weights[i] = 0;
11914  }
11915  else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11916  {
11917  /* job i runs after source and before sink */
11918  tcliquegraph->weights[i] = duration;
11919  }
11920  else if( lct <= SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var))
11921  && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11922  {
11923  /* job i run in between due the bounds of the start time variables */
11924  tcliquegraph->weights[i] = duration;
11925  }
11926  else
11927  tcliquegraph->weights[i] = 0;
11928  }
11929 
11930  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11931 
11932  /* find (heuristically) maximum cliques */
11933  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11934  tcliquegraph, tcliqueNewsolClique, NULL,
11935  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11936  10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11937 
11938  if( ncliquenodes > 1 )
11939  {
11940  char name[SCIP_MAXSTRLEN];
11941  int distance;
11942 
11943  /* construct constraint name */
11944  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11945 
11946  /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11947  * duration of the source job
11948  */
11949  distance = cliqueweight + tcliquegraph->durations[source];
11950 
11951  SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11952  (*naddconss)++;
11953  }
11954 
11955  SCIPfreeBufferArray(scip, &cliquenodes);
11956 
11957  return SCIP_OKAY;
11958 }
11959 
11960 /** search for precedence constraints
11961  *
11962  * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
11963  * corresponding two jobs
11964  */
11965 static
11967  SCIP* scip, /**< SCIP data structure */
11968  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11969  int* naddconss /**< pointer to store the number of added constraints */
11970  )
11971 {
11972  int* sources;
11973  int* sinks;
11974  int nconss;
11975  int nnodes;
11976  int nsources;
11977  int nsinks;
11978  int i;
11979 
11980  nnodes = tcliquegraph->nnodes;
11981  nconss = 0;
11982 
11983  nsources = 0;
11984  nsinks = 0;
11985 
11986  SCIP_CALL( SCIPallocBufferArray(scip, &sources, nnodes) );
11987  SCIP_CALL( SCIPallocBufferArray(scip, &sinks, nnodes) );
11988 
11989  /* first collect all sources and sinks */
11990  for( i = 0; i < nnodes; ++i )
11991  {
11992  if( tcliquegraph->ninarcs[i] == 0 )
11993  {
11994  sources[nsources] = i;
11995  nsources++;
11996  }
11997 
11998  if( tcliquegraph->ninarcs[i] == 0 )
11999  {
12000  sinks[nsinks] = i;
12001  nsinks++;
12002  }
12003  }
12004 
12005  /* compute for each node a minimum distance to each sources and each sink */
12006  for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
12007  {
12008  int j;
12009 
12010  for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
12011  {
12012  SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
12013  }
12014 
12015  for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
12016  {
12017  SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
12018  }
12019  }
12020 
12021  (*naddconss) += nconss;
12022 
12023  /* for the statistic we count the number added variable constraints */
12024  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
12025 
12026  SCIPfreeBufferArray(scip, &sinks);
12027  SCIPfreeBufferArray(scip, &sources);
12028 
12029  return SCIP_OKAY;
12030 }
12031 
12032 /** initialize the assumed durations for each variable */
12033 static
12035  SCIP* scip, /**< SCIP data structure */
12036  TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
12037  SCIP_CONS** conss, /**< cumulative constraints */
12038  int nconss /**< number of cumulative constraints */
12039  )
12040 {
12041  int c;
12042 
12043  /* use the cumulative structure to define the duration we are using for each job */
12044  for( c = 0; c < nconss; ++c )
12045  {
12046  SCIP_CONSDATA* consdata;
12047  SCIP_VAR** vars;
12048  int nvars;
12049  int v;
12050 
12051  consdata = SCIPconsGetData(conss[c]);
12052  assert(consdata != NULL);
12053 
12054  vars = consdata->vars;
12055  nvars = consdata->nvars;
12056 
12057  for( v = 0; v < nvars; ++v )
12058  {
12059  int idx;
12060 
12061  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12062  assert(idx >= 0);
12063 
12064  /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12065  * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12066  * general this is not the case. Therefore, the question would be which duration should be used?
12067  */
12068  tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12069  assert(tcliquegraph->durations[idx] > 0);
12070  }
12071  }
12072 
12073  return SCIP_OKAY;
12074 }
12075 
12076 /** create tclique graph */
12077 static
12079  SCIP* scip, /**< SCIP data structure */
12080  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12081  )
12082 {
12083  SCIP_VAR** vars;
12084  SCIP_HASHMAP* varmap;
12085  SCIP_Bool** precedencematrix;
12086  SCIP_Bool** demandmatrix;
12087  int* ninarcs;
12088  int* noutarcs;
12089  int* durations;
12090  int* weights;
12091  int nvars;
12092  int v;
12093 
12094  vars = SCIPgetVars(scip);
12095  nvars = SCIPgetNVars(scip);
12096 
12097  /* allocate memory for the tclique graph data structure */
12098  SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12099 
12100  /* create the variable mapping hash map */
12101  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
12102 
12103  /* each active variables get a node in the graph */
12104  SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12105 
12106  /* allocate memory for the projected variables bound graph and the none overlapping graph */
12107  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12108  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12109 
12110  /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12111  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12112  BMSclearMemoryArray(weights, nvars);
12113 
12114  /* array to store the number of in arc of the precedence graph */
12115  SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12116  BMSclearMemoryArray(ninarcs, nvars);
12117 
12118  /* array to store the number of out arc of the precedence graph */
12119  SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12120  BMSclearMemoryArray(noutarcs, nvars);
12121 
12122  /* array to store the used duration for each node */
12123  SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12124  BMSclearMemoryArray(durations, nvars);
12125 
12126  for( v = 0; v < nvars; ++v )
12127  {
12128  SCIP_VAR* var;
12129 
12130  var = vars[v];
12131  assert(var != NULL);
12132 
12133  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12134  BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12135 
12136  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12137  BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12138 
12139  /* insert all active variables into the garph */
12140  assert(SCIPvarGetProbindex(var) == v);
12141  SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)var, v) );
12142  }
12143 
12144  (*tcliquegraph)->nnodes = nvars;
12145  (*tcliquegraph)->varmap = varmap;
12146  (*tcliquegraph)->precedencematrix = precedencematrix;
12147  (*tcliquegraph)->demandmatrix = demandmatrix;
12148  (*tcliquegraph)->weights = weights;
12149  (*tcliquegraph)->ninarcs = ninarcs;
12150  (*tcliquegraph)->noutarcs = noutarcs;
12151  (*tcliquegraph)->durations = durations;
12152  (*tcliquegraph)->size = nvars;
12153 
12154  return SCIP_OKAY;
12155 }
12156 
12157 /** frees the tclique graph */
12158 static
12159 void freeTcliqueGraph(
12160  SCIP* scip, /**< SCIP data structure */
12161  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12162  )
12163 {
12164  int v;
12165 
12166  for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12167  {
12168  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12169  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12170  }
12171 
12172  SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12173  SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12174  SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12175  SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12176  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12177  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12178  SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12179  SCIPhashmapFree(&(*tcliquegraph)->varmap);
12180 
12181  SCIPfreeBuffer(scip, tcliquegraph);
12182 }
12183 
12184 /** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12185  * constrains (disjunctive constraint)
12186  */
12187 static
12189  SCIP* scip, /**< SCIP data structure */
12190  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12191  SCIP_CONS** conss, /**< array of cumulative constraints */
12192  int nconss, /**< number of cumulative constraints */
12193  int* naddconss /**< pointer to store the number of added constraints */
12194  )
12195 {
12196  TCLIQUE_GRAPH* tcliquegraph;
12197 
12198  /* create tclique graph */
12199  SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12200 
12201  /* define for each job a duration */
12202  SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12203 
12204  /* constuct incompatibility graph */
12205  SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12206 
12207  /* search for new precedence constraints */
12208  if( conshdlrdata->detectvarbounds )
12209  {
12210  SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12211  }
12212 
12213  /* search for new cumulative constraints */
12214  if( conshdlrdata->detectdisjunctive )
12215  {
12216  SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12217  }
12218 
12219  /* free tclique graph data structure */
12220  freeTcliqueGraph(scip, &tcliquegraph);
12221 
12222  return SCIP_OKAY;
12223 }
12224 
12225 /** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12226 static
12228  SCIP_CONSDATA* consdata /**< cumulative constraint data */
12229  )
12230 {
12231  SCIP_VAR** vars;
12232  int nvars;
12233  int v;
12234 
12235  if( consdata->validsignature )
12236  return;
12237 
12238  vars = consdata->vars;
12239  nvars = consdata->nvars;
12240 
12241  for( v = 0; v < nvars; ++v )
12242  {
12243  consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12244  }
12245 
12246  consdata->validsignature = TRUE;
12247 }
12248 
12249 /** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12250 static
12251 SCIP_DECL_SORTINDCOMP(consdataCompVar)
12252 { /*lint --e{715}*/
12253  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12254 
12255  assert(consdata != NULL);
12256  assert(0 <= ind1 && ind1 < consdata->nvars);
12257  assert(0 <= ind2 && ind2 < consdata->nvars);
12258 
12259  return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12260 }
12261 
12262 /** run a pairwise comparison */
12263 static
12265  SCIP* scip, /**< SCIP data structure */
12266  SCIP_CONS** conss, /**< array of cumulative constraints */
12267  int nconss, /**< number of cumulative constraints */
12268  int* ndelconss /**< pointer to store the number of deletedconstraints */
12269  )
12270 {
12271  int i;
12272  int j;
12273 
12274  for( i = 0; i < nconss; ++i )
12275  {
12276  SCIP_CONSDATA* consdata0;
12277  SCIP_CONS* cons0;
12278 
12279  cons0 = conss[i];
12280  assert(cons0 != NULL);
12281 
12282  consdata0 = SCIPconsGetData(cons0);
12283  assert(consdata0 != NULL);
12284 
12285  consdataCalcSignature(consdata0);
12286  assert(consdata0->validsignature);
12287 
12288  for( j = i+1; j < nconss; ++j )
12289  {
12290  SCIP_CONSDATA* consdata1;
12291  SCIP_CONS* cons1;
12292 
12293  cons1 = conss[j];
12294  assert(cons1 != NULL);
12295 
12296  consdata1 = SCIPconsGetData(cons1);
12297  assert(consdata1 != NULL);
12298 
12299  if( consdata0->capacity != consdata1->capacity )
12300  continue;
12301 
12302  consdataCalcSignature(consdata1);
12303  assert(consdata1->validsignature);
12304 
12305  if( (consdata1->signature & (~consdata0->signature)) == 0 )
12306  {
12307  SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12308  SCIPswapPointers((void**)&cons0, (void**)&cons1);
12309  assert((consdata0->signature & (~consdata1->signature)) == 0);
12310  }
12311 
12312  if( (consdata0->signature & (~consdata1->signature)) == 0 )
12313  {
12314  int* perm0;
12315  int* perm1;
12316  int v0;
12317  int v1;
12318 
12319  if( consdata0->nvars > consdata1->nvars )
12320  continue;
12321 
12322  if( consdata0->hmin < consdata1->hmin )
12323  continue;
12324 
12325  if( consdata0->hmax > consdata1->hmax )
12326  continue;
12327 
12328  SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12329  SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12330 
12331  /* call sorting method */
12332  SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12333  SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12334 
12335  for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12336  {
12337  SCIP_VAR* var0;
12338  SCIP_VAR* var1;
12339  int idx0;
12340  int idx1;
12341  int comp;
12342 
12343  idx0 = perm0[v0];
12344  idx1 = perm1[v1];
12345 
12346  var0 = consdata0->vars[idx0];
12347 
12348  var1 = consdata1->vars[idx1];
12349 
12350  comp = SCIPvarCompare(var0, var1);
12351 
12352  if( comp == 0 )
12353  {
12354  int duration0;
12355  int duration1;
12356  int demand0;
12357  int demand1;
12358 
12359  demand0 = consdata0->demands[idx0];
12360  duration0 = consdata0->durations[idx0];
12361 
12362  demand1 = consdata1->demands[idx1];
12363  duration1 = consdata1->durations[idx1];
12364 
12365  if( demand0 != demand1 )
12366  break;
12367 
12368  if( duration0 != duration1 )
12369  break;
12370 
12371  v0++;
12372  v1++;
12373  }
12374  else if( comp > 0 )
12375  v1++;
12376  else
12377  break;
12378  }
12379 
12380  if( v0 == consdata0->nvars )
12381  {
12382  if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12383  {
12384  initializeLocks(consdata1, TRUE);
12385  }
12386 
12387  /* coverity[swapped_arguments] */
12388  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12389 
12390  SCIP_CALL( SCIPdelCons(scip, cons0) );
12391  (*ndelconss)++;
12392  }
12393 
12394  SCIPfreeBufferArray(scip, &perm1);
12395  SCIPfreeBufferArray(scip, &perm0);
12396  }
12397  }
12398  }
12399 
12400  return SCIP_OKAY;
12401 }
12402 
12403 /** strengthen the variable bounds using the cumulative condition */
12404 static
12406  SCIP* scip, /**< SCIP data structure */
12407  SCIP_CONS* cons, /**< constraint to propagate */
12408  int* nchgbds, /**< pointer to store the number of changed bounds */
12409  int* naddconss /**< pointer to store the number of added constraints */
12410  )
12411 {
12412  SCIP_CONSDATA* consdata;
12413  SCIP_VAR** vars;
12414  int* durations;
12415  int* demands;
12416  int capacity;
12417  int nvars;
12418  int nconss;
12419  int i;
12420 
12421  consdata = SCIPconsGetData(cons);
12422  assert(consdata != NULL);
12423 
12424  /* check if the variable bounds got already strengthen by the cumulative constraint */
12425  if( consdata->varbounds )
12426  return SCIP_OKAY;
12427 
12428  vars = consdata->vars;
12429  durations = consdata->durations;
12430  demands = consdata->demands;
12431  capacity = consdata->capacity;
12432  nvars = consdata->nvars;
12433 
12434  nconss = 0;
12435 
12436  for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12437  {
12438  SCIP_VAR** vbdvars;
12439  SCIP_VAR* var;
12440  SCIP_Real* vbdcoefs;
12441  SCIP_Real* vbdconsts;
12442  int nvbdvars;
12443  int b;
12444  int j;
12445 
12446  var = consdata->vars[i];
12447  assert(var != NULL);
12448 
12449  vbdvars = SCIPvarGetVlbVars(var);
12450  vbdcoefs = SCIPvarGetVlbCoefs(var);
12451  vbdconsts = SCIPvarGetVlbConstants(var);
12452  nvbdvars = SCIPvarGetNVlbs(var);
12453 
12454  for( b = 0; b < nvbdvars; ++b )
12455  {
12456  if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12457  {
12458  if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12459  {
12460  for( j = 0; j < nvars; ++j )
12461  {
12462  if( vars[j] == vbdvars[b] )
12463  break;
12464  }
12465  if( j == nvars )
12466  continue;
12467 
12468  if( demands[i] + demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12469  {
12470  SCIP_Bool infeasible;
12471  char name[SCIP_MAXSTRLEN];
12472  int nlocalbdchgs;
12473 
12474  SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12475 
12476  /* construct constraint name */
12477  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12478 
12479  SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12480  nconss++;
12481 
12482  SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12483  assert(!infeasible);
12484 
12485  (*nchgbds) += nlocalbdchgs;
12486  }
12487  }
12488  }
12489  }
12490  }
12491 
12492  (*naddconss) += nconss;
12493 
12494  consdata->varbounds = TRUE;
12495 
12496  return SCIP_OKAY;
12497 }
12498 
12499 /** helper function to enforce constraints */
12500 static
12502  SCIP* scip, /**< SCIP data structure */
12503  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
12504  SCIP_CONS** conss, /**< constraints to process */
12505  int nconss, /**< number of constraints */
12506  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
12507  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
12508  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
12509  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
12510  )
12511 {
12512  SCIP_CONSHDLRDATA* conshdlrdata;
12513 
12514  assert(conshdlr != NULL);
12515  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12516  assert(nconss == 0 || conss != NULL);
12517  assert(result != NULL);
12518 
12519  if( solinfeasible )
12520  {
12521  *result = SCIP_INFEASIBLE;
12522  return SCIP_OKAY;
12523  }
12524 
12525  SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12526  sol == NULL ? "LP" : "relaxation");
12527 
12528  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12529  assert(conshdlrdata != NULL);
12530 
12531  (*result) = SCIP_FEASIBLE;
12532 
12533  if( conshdlrdata->usebinvars )
12534  {
12535  SCIP_Bool separated;
12536  SCIP_Bool cutoff;
12537  int c;
12538 
12539  separated = FALSE;
12540 
12541  /* first check if a constraints is violated */
12542  for( c = 0; c < nusefulconss; ++c )
12543  {
12544  SCIP_CONS* cons;
12545  SCIP_Bool violated;
12546 
12547  cons = conss[c];
12548  assert(cons != NULL);
12549 
12550  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12551 
12552  if( !violated )
12553  continue;
12554 
12555  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12556  if ( cutoff )
12557  {
12558  *result = SCIP_CUTOFF;
12559  return SCIP_OKAY;
12560  }
12561  }
12562 
12563  for( ; c < nconss && !separated; ++c )
12564  {
12565  SCIP_CONS* cons;
12566  SCIP_Bool violated;
12567 
12568  cons = conss[c];
12569  assert(cons != NULL);
12570 
12571  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12572 
12573  if( !violated )
12574  continue;
12575 
12576  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12577  if ( cutoff )
12578  {
12579  *result = SCIP_CUTOFF;
12580  return SCIP_OKAY;
12581  }
12582  }
12583 
12584  if( separated )
12585  (*result) = SCIP_SEPARATED;
12586  }
12587  else
12588  {
12589  SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12590  }
12591 
12592  return SCIP_OKAY;
12593 }
12594 
12595 /**@} */
12596 
12597 
12598 /**@name Callback methods of constraint handler
12599  *
12600  * @{
12601  */
12602 
12603 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12604 static
12605 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12606 { /*lint --e{715}*/
12607  assert(scip != NULL);
12608  assert(conshdlr != NULL);
12609  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12610 
12611  /* call inclusion method of constraint handler */
12613 
12615 
12616  *valid = TRUE;
12617 
12618  return SCIP_OKAY;
12619 }
12620 
12621 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12622 static
12623 SCIP_DECL_CONSFREE(consFreeCumulative)
12624 { /*lint --e{715}*/
12625  SCIP_CONSHDLRDATA* conshdlrdata;
12626 
12627  assert(conshdlr != NULL);
12628  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12629 
12630  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12631  assert(conshdlrdata != NULL);
12632 
12633 #ifdef SCIP_STATISTIC
12634  if( !conshdlrdata->iscopy )
12635  {
12636  /* statisitc output if SCIP_STATISTIC is defined */
12637  SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12638  conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12639  SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12640  conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12641  SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12642  conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12643  }
12644 #endif
12645 
12646  conshdlrdataFree(scip, &conshdlrdata);
12647 
12648  SCIPconshdlrSetData(conshdlr, NULL);
12649 
12650  return SCIP_OKAY;
12651 }
12652 
12653 
12654 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12655 static
12656 SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12657 { /*lint --e{715}*/
12658  SCIP_CONSHDLRDATA* conshdlrdata;
12659  int c;
12660 
12661  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12662  assert(conshdlrdata != NULL);
12663 
12664  conshdlrdata->detectedredundant = FALSE;
12665 
12666  for( c = 0; c < nconss; ++c )
12667  {
12668  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12669  * hmax)
12670  */
12671  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12672  }
12673 
12674  return SCIP_OKAY;
12675 }
12676 
12677 
12678 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12679 #ifdef SCIP_STATISTIC
12680 static
12681 SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12682 { /*lint --e{715}*/
12683  SCIP_CONSHDLRDATA* conshdlrdata;
12684  int c;
12685 
12686  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12687  assert(conshdlrdata != NULL);
12688 
12689  for( c = 0; c < nconss; ++c )
12690  {
12691  SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12692 
12693 #if 0
12694  SCIP_CALL( SCIPvisualizeConsCumulative(scip, conss[c]) );
12695 #endif
12696  }
12697 
12698  if( !conshdlrdata->iscopy )
12699  {
12700  SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12701  SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12702  SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12703  SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12704  SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12705  SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12706  SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12707  SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12708  SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12709  }
12710 
12711  return SCIP_OKAY;
12712 }
12713 #endif
12714 
12715 
12716 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12717 static
12718 SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12719 { /*lint --e{715}*/
12720  SCIP_CONSDATA* consdata;
12721  int c;
12722 
12723  assert(conshdlr != NULL);
12724  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12725 
12726  /* release the rows of all constraints */
12727  for( c = 0; c < nconss; ++c )
12728  {
12729  consdata = SCIPconsGetData(conss[c]);
12730  assert(consdata != NULL);
12731 
12732  /* free rows */
12733  SCIP_CALL( consdataFreeRows(scip, &consdata) );
12734  }
12735 
12736  return SCIP_OKAY;
12737 }
12738 
12739 /** frees specific constraint data */
12740 static
12741 SCIP_DECL_CONSDELETE(consDeleteCumulative)
12742 { /*lint --e{715}*/
12743  assert(conshdlr != NULL);
12744  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12745  assert(consdata != NULL );
12746  assert(*consdata != NULL );
12747 
12748  /* if constraint belongs to transformed problem space, drop bound change events on variables */
12749  if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12750  {
12751  SCIP_CONSHDLRDATA* conshdlrdata;
12752 
12753  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12754  assert(conshdlrdata != NULL);
12755 
12756  SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12757  }
12758 
12759  /* free cumulative constraint data */
12760  SCIP_CALL( consdataFree(scip, consdata) );
12761 
12762  return SCIP_OKAY;
12763 }
12764 
12765 /** transforms constraint data into data belonging to the transformed problem */
12766 static
12767 SCIP_DECL_CONSTRANS(consTransCumulative)
12768 { /*lint --e{715}*/
12769  SCIP_CONSHDLRDATA* conshdlrdata;
12770  SCIP_CONSDATA* sourcedata;
12771  SCIP_CONSDATA* targetdata;
12772 
12773  assert(conshdlr != NULL);
12774  assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
12775  assert(sourcecons != NULL);
12776  assert(targetcons != NULL);
12777 
12778  sourcedata = SCIPconsGetData(sourcecons);
12779  assert(sourcedata != NULL);
12780  assert(sourcedata->demandrows == NULL);
12781 
12782  SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12783 
12784  /* get event handler */
12785  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12786  assert(conshdlrdata != NULL);
12787  assert(conshdlrdata->eventhdlr != NULL);
12788 
12789  /* create constraint data for target constraint */
12790  SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12791  sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12792  sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12793 
12794  /* create target constraint */
12795  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12796  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12797  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12798  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12799  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12800 
12801  /* catch bound change events of variables */
12802  SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12803 
12804  return SCIP_OKAY;
12805 }
12806 
12807 /** LP initialization method of constraint handler */
12808 static
12809 SCIP_DECL_CONSINITLP(consInitlpCumulative)
12811  SCIP_CONSHDLRDATA* conshdlrdata;
12812  int c;
12813 
12814  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12815  assert(conshdlr != NULL);
12816  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12817  assert(conshdlrdata != NULL);
12818 
12819  *infeasible = FALSE;
12820 
12821  SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12822 
12823  if( conshdlrdata->usebinvars )
12824  {
12825  /* add rows to LP */
12826  for( c = 0; c < nconss && !(*infeasible); ++c )
12827  {
12828  assert(SCIPconsIsInitial(conss[c]));
12829  SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12830 
12831  if( conshdlrdata->cutsasconss )
12832  {
12833  SCIP_CALL( SCIPrestartSolve(scip) );
12834  }
12835  }
12836  }
12837 
12838  /**@todo if we want to use only the integer variables; only these will be in cuts
12839  * create some initial cuts, currently these are only separated */
12840 
12841  return SCIP_OKAY;
12842 }
12843 
12844 /** separation method of constraint handler for LP solutions */
12845 static
12846 SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12848  SCIP_CONSHDLRDATA* conshdlrdata;
12849  SCIP_Bool cutoff;
12850  SCIP_Bool separated;
12851  int c;
12852 
12853  SCIPdebugMsg(scip, "consSepalpCumulative\n");
12854 
12855  assert(conshdlr != NULL);
12856  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12857  assert(nconss == 0 || conss != NULL);
12858  assert(result != NULL);
12859  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12860  assert(conshdlrdata != NULL);
12861 
12862  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12863 
12864  cutoff = FALSE;
12865  separated = FALSE;
12866  (*result) = SCIP_DIDNOTRUN;
12867 
12868  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12869  return SCIP_OKAY;
12870 
12871  (*result) = SCIP_DIDNOTFIND;
12872 
12873  if( conshdlrdata->usebinvars )
12874  {
12875  /* check all useful cumulative constraints for feasibility */
12876  for( c = 0; c < nusefulconss && !cutoff; ++c )
12877  {
12878  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12879  }
12880 
12881  if( !cutoff && conshdlrdata->usecovercuts )
12882  {
12883  for( c = 0; c < nusefulconss; ++c )
12884  {
12885  SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12886  }
12887  }
12888  }
12889 
12890  if( conshdlrdata->sepaold )
12891  {
12892  /* separate cuts containing only integer variables */
12893  for( c = 0; c < nusefulconss; ++c )
12894  {
12895  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12896  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12897  }
12898  }
12899 
12900  if( cutoff )
12901  *result = SCIP_CUTOFF;
12902  else if( separated )
12903  *result = SCIP_SEPARATED;
12904 
12905  return SCIP_OKAY;
12906 }
12907 
12908 /** separation method of constraint handler for arbitrary primal solutions */
12909 static
12910 SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12911 { /*lint --e{715}*/
12912  SCIP_CONSHDLRDATA* conshdlrdata;
12913  SCIP_Bool cutoff;
12914  SCIP_Bool separated;
12915  int c;
12916 
12917  assert(conshdlr != NULL);
12918  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12919  assert(nconss == 0 || conss != NULL);
12920  assert(result != NULL);
12921 
12922  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12923  assert(conshdlrdata != NULL);
12924 
12925  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12926  return SCIP_OKAY;
12927 
12928  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12929 
12930  cutoff = FALSE;
12931  separated = FALSE;
12932  (*result) = SCIP_DIDNOTFIND;
12933 
12934  if( conshdlrdata->usebinvars )
12935  {
12936  /* check all useful cumulative constraints for feasibility */
12937  for( c = 0; c < nusefulconss && !cutoff; ++c )
12938  {
12939  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12940  }
12941 
12942  if( !cutoff && conshdlrdata->usecovercuts )
12943  {
12944  for( c = 0; c < nusefulconss; ++c )
12945  {
12946  SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12947  }
12948  }
12949  }
12950  if( conshdlrdata->sepaold )
12951  {
12952  /* separate cuts containing only integer variables */
12953  for( c = 0; c < nusefulconss; ++c )
12954  {
12955  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12956  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12957  }
12958  }
12959 
12960  if( cutoff )
12961  *result = SCIP_CUTOFF;
12962  else if( separated )
12963  *result = SCIP_SEPARATED;
12964 
12965  return SCIP_OKAY;
12966 }
12967 
12968 /** constraint enforcing method of constraint handler for LP solutions */
12969 static
12970 SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
12971 { /*lint --e{715}*/
12972  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
12973 
12974  return SCIP_OKAY;
12975 }
12976 
12977 /** constraint enforcing method of constraint handler for relaxation solutions */
12978 static
12979 SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
12980 { /*lint --e{715}*/
12981  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
12982 
12983  return SCIP_OKAY;
12984 }
12985 
12986 /** constraint enforcing method of constraint handler for pseudo solutions */
12987 static
12988 SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
12989 { /*lint --e{715}*/
12990  SCIP_CONSHDLRDATA* conshdlrdata;
12991 
12992  SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
12993 
12994  assert(conshdlr != NULL);
12995  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12996  assert(nconss == 0 || conss != NULL);
12997  assert(result != NULL);
12998 
12999  if( objinfeasible )
13000  {
13001  *result = SCIP_DIDNOTRUN;
13002  return SCIP_OKAY;
13003  }
13004 
13005  (*result) = SCIP_FEASIBLE;
13006 
13007  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13008  assert(conshdlrdata != NULL);
13009 
13010  SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
13011 
13012  return SCIP_OKAY;
13013 }
13014 
13015 /** feasibility check method of constraint handler for integral solutions */
13016 static
13017 SCIP_DECL_CONSCHECK(consCheckCumulative)
13018 { /*lint --e{715}*/
13019  int c;
13020 
13021  assert(conshdlr != NULL);
13022  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13023  assert(nconss == 0 || conss != NULL);
13024  assert(result != NULL);
13025 
13026  *result = SCIP_FEASIBLE;
13027 
13028  SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
13029 
13030  for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
13031  {
13032  SCIP_Bool violated = FALSE;
13033 
13034  SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
13035 
13036  if( violated )
13037  *result = SCIP_INFEASIBLE;
13038  }
13039 
13040  return SCIP_OKAY;
13041 }
13042 
13043 /** domain propagation method of constraint handler */
13044 static
13045 SCIP_DECL_CONSPROP(consPropCumulative)
13046 { /*lint --e{715}*/
13047  SCIP_CONSHDLRDATA* conshdlrdata;
13048  SCIP_Bool cutoff;
13049  int nchgbds;
13050  int ndelconss;
13051  int c;
13052 #if 0
13053  int naggrvars = 0;
13054 #endif
13055 
13056  SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
13057 
13058  assert(conshdlr != NULL);
13059  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13060  assert(nconss == 0 || conss != NULL);
13061  assert(result != NULL);
13062 
13063  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13064  assert(conshdlrdata != NULL);
13065 
13066  nchgbds = 0;
13067  ndelconss = 0;
13068  cutoff = FALSE;
13069  (*result) = SCIP_DIDNOTRUN;
13070 
13071  /* propgate all useful constraints */
13072  for( c = 0; c < nusefulconss && !cutoff; ++c )
13073  {
13074  SCIP_CONS* cons;
13075 
13076  cons = conss[c];
13077  assert(cons != NULL);
13078 
13079  if( SCIPgetDepth(scip) == 0 )
13080  {
13081 #if 0
13082  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13083  &nchgbds, &naggrvars, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13084 #else
13085  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13086  &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13087 #endif
13088  if( cutoff )
13089  break;
13090 
13091  if( SCIPconsIsDeleted(cons) )
13092  continue;
13093  }
13094 
13095  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13096  }
13097 
13098  if( !cutoff && nchgbds == 0 )
13099  {
13100  /* propgate all other constraints */
13101  for( c = nusefulconss; c < nconss && !cutoff; ++c )
13102  {
13103  SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13104  }
13105  }
13106 
13107 #if 0
13108  if( !cutoff && conshdlrdata->dualpresolve && SCIPallowDualReds(scip) && nconss > 1 )
13109  {
13110  SCIP_CALL( propagateAllConss(scip, conshdlrdata, conss, nconss, TRUE, &nchgbds, &cutoff, NULL) );
13111  }
13112 #endif
13113 
13114  if( cutoff )
13115  {
13116  SCIPdebugMsg(scip, "detected infeasible\n");
13117  *result = SCIP_CUTOFF;
13118  }
13119  else if( nchgbds > 0 )
13120  {
13121  SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13122  *result = SCIP_REDUCEDDOM;
13123  }
13124  else
13125  *result = SCIP_DIDNOTFIND;
13126 
13127  return SCIP_OKAY;
13128 }
13129 
13130 /** presolving method of constraint handler */
13131 static
13132 SCIP_DECL_CONSPRESOL(consPresolCumulative)
13133 { /*lint --e{715}*/
13134  SCIP_CONSHDLRDATA* conshdlrdata;
13135  SCIP_CONS* cons;
13136  SCIP_Bool cutoff;
13137  SCIP_Bool unbounded;
13138  int oldnfixedvars;
13139  int oldnchgbds;
13140  int oldndelconss;
13141  int oldnaddconss;
13142  int oldnupgdconss;
13143  int oldnchgsides;
13144  int oldnchgcoefs;
13145  int c;
13146 
13147  assert(conshdlr != NULL);
13148  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13149  assert(scip != NULL);
13150  assert(result != NULL);
13151 
13152  SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13153 
13154  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13155  assert(conshdlrdata != NULL);
13156 
13157  *result = SCIP_DIDNOTRUN;
13158 
13159  oldnfixedvars = *nfixedvars;
13160  oldnchgbds = *nchgbds;
13161  oldnchgsides = *nchgsides;
13162  oldnchgcoefs = *nchgcoefs;
13163  oldnupgdconss = *nupgdconss;
13164  oldndelconss = *ndelconss;
13165  oldnaddconss = *naddconss;
13166  cutoff = FALSE;
13167  unbounded = FALSE;
13168 
13169  /* process constraints */
13170  for( c = 0; c < nconss && !cutoff; ++c )
13171  {
13172  cons = conss[c];
13173 
13174  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13175  * hmax)
13176  */
13177  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13178 
13179  if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13180  {
13181 #if 0
13182  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13183  nfixedvars, naggrvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13184 #else
13185  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13186  nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13187 #endif
13188 
13189  if( cutoff || unbounded )
13190  break;
13191 
13192  if( SCIPconsIsDeleted(cons) )
13193  continue;
13194  }
13195 
13196  /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13197  if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13198  {
13199  SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13200  }
13201 
13202  /* strengthen existing variable bounds using the cumulative condition */
13203  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13204  {
13205  SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13206  }
13207 
13208  /* propagate cumulative constraint */
13209  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13210  assert(checkDemands(scip, cons) || cutoff);
13211  }
13212 
13213  if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13214  {
13215  SCIP_CALL( propagateAllConss(scip, conshdlrdata, conss, nconss, FALSE,
13216  nfixedvars, &cutoff, NULL) );
13217  }
13218 
13219  /* only perform the detection of variable bounds and disjunctive constraint once */
13220  if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13221  && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13222  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13223  {
13224  /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13225  * propagation
13226  */
13227  SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13228  conshdlrdata->detectedredundant = TRUE;
13229  }
13230 
13231  if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13232  {
13233  SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13234  }
13235 
13236  SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13237  *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13238 
13239  if( cutoff )
13240  *result = SCIP_CUTOFF;
13241  else if( unbounded )
13242  *result = SCIP_UNBOUNDED;
13243  else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13244  || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13245  *result = SCIP_SUCCESS;
13246  else
13247  *result = SCIP_DIDNOTFIND;
13248 
13249  return SCIP_OKAY;
13250 }
13251 
13252 /** propagation conflict resolving method of constraint handler */
13253 static
13254 SCIP_DECL_CONSRESPROP(consRespropCumulative)
13255 { /*lint --e{715}*/
13256  SCIP_CONSHDLRDATA* conshdlrdata;
13257  SCIP_CONSDATA* consdata;
13258 
13259  assert(conshdlr != NULL);
13260  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13261  assert(scip != NULL);
13262  assert(result != NULL);
13263  assert(infervar != NULL);
13264  assert(bdchgidx != NULL);
13265 
13266  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13267  assert(conshdlrdata != NULL);
13268 
13269  /* process constraint */
13270  assert(cons != NULL);
13271 
13272  consdata = SCIPconsGetData(cons);
13273  assert(consdata != NULL);
13274 
13275  SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13276  SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13277  SCIPgetHminCumulative(scip, cons), SCIPgetHmaxCumulative(scip, cons));
13278 
13279  SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13280  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13281  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13282 
13283  return SCIP_OKAY;
13284 }
13285 
13286 /** variable rounding lock method of constraint handler */
13287 static
13288 SCIP_DECL_CONSLOCK(consLockCumulative)
13289 { /*lint --e{715}*/
13290  SCIP_CONSDATA* consdata;
13291  SCIP_VAR** vars;
13292  int v;
13293 
13294  SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13295 
13296  assert(scip != NULL);
13297  assert(cons != NULL);
13298  assert(locktype == SCIP_LOCKTYPE_MODEL);
13299 
13300  consdata = SCIPconsGetData(cons);
13301  assert(consdata != NULL);
13302 
13303  vars = consdata->vars;
13304  assert(vars != NULL);
13305 
13306  for( v = 0; v < consdata->nvars; ++v )
13307  {
13308  if( consdata->downlocks[v] && consdata->uplocks[v] )
13309  {
13310  /* the integer start variable should not get rounded in both direction */
13311  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
13312  }
13313  else if( consdata->downlocks[v] )
13314  {
13315  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
13316  }
13317  else if( consdata->uplocks[v] )
13318  {
13319  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
13320  }
13321  }
13322 
13323  return SCIP_OKAY;
13324 }
13325 
13326 
13327 /** constraint display method of constraint handler */
13328 static
13329 SCIP_DECL_CONSPRINT(consPrintCumulative)
13330 { /*lint --e{715}*/
13331  assert(scip != NULL);
13332  assert(conshdlr != NULL);
13333  assert(cons != NULL);
13334 
13335  consdataPrint(scip, SCIPconsGetData(cons), file);
13336 
13337  return SCIP_OKAY;
13338 }
13339 
13340 /** constraint copying method of constraint handler */
13341 static
13342 SCIP_DECL_CONSCOPY(consCopyCumulative)
13343 { /*lint --e{715}*/
13344  SCIP_CONSDATA* sourceconsdata;
13345  SCIP_VAR** sourcevars;
13346  SCIP_VAR** vars;
13347  const char* consname;
13348 
13349  int nvars;
13350  int v;
13351 
13352  sourceconsdata = SCIPconsGetData(sourcecons);
13353  assert(sourceconsdata != NULL);
13354 
13355  /* get variables of the source constraint */
13356  nvars = sourceconsdata->nvars;
13357  sourcevars = sourceconsdata->vars;
13358 
13359  (*valid) = TRUE;
13360 
13361  if( nvars == 0 )
13362  return SCIP_OKAY;
13363 
13364  /* allocate buffer array */
13365  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13366 
13367  for( v = 0; v < nvars && *valid; ++v )
13368  {
13369  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13370  assert(!(*valid) || vars[v] != NULL);
13371  }
13372 
13373  /* only create the target constraint, if all variables could be copied */
13374  if( *valid )
13375  {
13376  if( name != NULL )
13377  consname = name;
13378  else
13379  consname = SCIPconsGetName(sourcecons);
13380 
13381  /* create a copy of the cumulative constraint */
13382  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13383  sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13384  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13385 
13386  /* adjust left side if the time axis if needed */
13387  if( sourceconsdata->hmin > 0 )
13388  {
13389  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13390  }
13391 
13392  /* adjust right side if the time axis if needed */
13393  if( sourceconsdata->hmax < INT_MAX )
13394  {
13395  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13396  }
13397  }
13398 
13399  /* free buffer array */
13400  SCIPfreeBufferArray(scip, &vars);
13401 
13402  return SCIP_OKAY;
13403 }
13404 
13405 
13406 /** constraint parsing method of constraint handler */
13407 static
13408 SCIP_DECL_CONSPARSE(consParseCumulative)
13409 { /*lint --e{715}*/
13410  SCIP_VAR** vars;
13411  SCIP_VAR* var;
13412  SCIP_Real value;
13413  char strvalue[SCIP_MAXSTRLEN];
13414  char* endptr;
13415  int* demands;
13416  int* durations;
13417  int capacity;
13418  int duration;
13419  int demand;
13420  int hmin;
13421  int hmax;
13422  int varssize;
13423  int nvars;
13424 
13425  SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13426 
13427  /* cutoff "cumulative" form the constraint string */
13428  SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13429  str = endptr;
13430 
13431  varssize = 100;
13432  nvars = 0;
13433 
13434  /* allocate buffer array for variables */
13435  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13436  SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13437  SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13438 
13439  do
13440  {
13441  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13442 
13443  if( var != NULL )
13444  {
13445  str = endptr;
13446 
13447  SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13448  duration = atoi(strvalue);
13449  str = endptr;
13450 
13451  SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13452  demand = atoi(strvalue);
13453  str = endptr;
13454 
13455  SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13456 
13457  vars[nvars] = var;
13458  demands[nvars] = demand;
13459  durations[nvars] = duration;
13460  nvars++;
13461  }
13462  }
13463  while( var != NULL );
13464 
13465  /* parse effective time window */
13466  SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13467  hmin = atoi(strvalue);
13468  str = endptr;
13469 
13470  if( SCIPstrToRealValue(str, &value, &endptr) )
13471  {
13472  hmax = (int)(value);
13473  str = endptr;
13474 
13475  /* parse capacity */
13476  SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13477  str = endptr;
13478  if( SCIPstrToRealValue(str, &value, &endptr) )
13479  {
13480  capacity = (int)value;
13481 
13482  /* create cumulative constraint */
13483  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13484  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13485 
13486  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13487  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13488 
13489  (*success) = TRUE;
13490  }
13491  }
13492 
13493  /* free buffer arrays */
13494  SCIPfreeBufferArray(scip, &durations);
13495  SCIPfreeBufferArray(scip, &demands);
13496  SCIPfreeBufferArray(scip, &vars);
13497 
13498  return SCIP_OKAY;
13499 }
13500 
13501 /** constraint method of constraint handler which returns the variables (if possible) */
13502 static
13503 SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13504 { /*lint --e{715}*/
13505  SCIP_CONSDATA* consdata;
13506 
13507  consdata = SCIPconsGetData(cons);
13508  assert(consdata != NULL);
13509 
13510  if( varssize < consdata->nvars )
13511  (*success) = FALSE;
13512  else
13513  {
13514  assert(vars != NULL);
13515 
13516  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13517  (*success) = TRUE;
13518  }
13519 
13520  return SCIP_OKAY;
13521 }
13522 
13523 /** constraint method of constraint handler which returns the number of variables (if possible) */
13524 static
13525 SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13526 { /*lint --e{715}*/
13527  SCIP_CONSDATA* consdata;
13528 
13529  consdata = SCIPconsGetData(cons);
13530  assert(consdata != NULL);
13531 
13532  (*nvars) = consdata->nvars;
13533  (*success) = TRUE;
13534 
13535  return SCIP_OKAY;
13536 }
13537 
13538 /**@} */
13539 
13540 /**@name Callback methods of event handler
13541  *
13542  * @{
13543  */
13544 
13545 
13546 /** execution method of event handler */
13547 static
13548 SCIP_DECL_EVENTEXEC(eventExecCumulative)
13549 { /*lint --e{715}*/
13550  SCIP_CONSDATA* consdata;
13551 
13552  assert(scip != NULL);
13553  assert(eventhdlr != NULL);
13554  assert(eventdata != NULL);
13555  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13556  assert(event != NULL);
13557 
13558  consdata = (SCIP_CONSDATA*)eventdata;
13559  assert(consdata != NULL);
13560 
13561  /* mark the constraint to be not propagated */
13562  consdata->propagated = FALSE;
13563 
13564  return SCIP_OKAY;
13565 }
13566 
13567 /**@} */
13568 
13569 /**@name Interface methods
13570  *
13571  * @{
13572  */
13573 
13574 /*
13575  * constraint specific interface methods
13576  */
13577 
13578 /** creates the handler for cumulative constraints and includes it in SCIP */
13580  SCIP* scip /**< SCIP data structure */
13581  )
13582 {
13583  SCIP_CONSHDLRDATA* conshdlrdata;
13584  SCIP_CONSHDLR* conshdlr;
13585  SCIP_EVENTHDLR* eventhdlr;
13586 
13587  /* create event handler for bound change events */
13588  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13589 
13590  /* create cumulative constraint handler data */
13591  SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13592 
13593  /* include constraint handler */
13596  consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13597  conshdlrdata) );
13598 
13599  assert(conshdlr != NULL);
13600 
13601  /* set non-fundamental callbacks via specific setter functions */
13602  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13603  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13604 #ifdef SCIP_STATISTIC
13605  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13606 #endif
13607  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13608  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13609  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13610  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13611  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13612  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13613  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13614  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13616  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13617  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropCumulative, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13619  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13620  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13622  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13623  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
13624 
13625  /* add cumulative constraint handler parameters */
13627  "constraints/" CONSHDLR_NAME "/ttinfer",
13628  "should time-table (core-times) propagator be used to infer bounds?",
13629  &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13631  "constraints/" CONSHDLR_NAME "/efcheck",
13632  "should edge-finding be used to detect an overload?",
13633  &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13635  "constraints/" CONSHDLR_NAME "/efinfer",
13636  "should edge-finding be used to infer bounds?",
13637  &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13639  "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13640  &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13642  "constraints/" CONSHDLR_NAME "/ttefcheck",
13643  "should time-table edge-finding be used to detect an overload?",
13644  &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13646  "constraints/" CONSHDLR_NAME "/ttefinfer",
13647  "should time-table edge-finding be used to infer bounds?",
13648  &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13649 
13651  "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13652  &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13654  "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13655  &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13657  "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13658  &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13660  "constraints/" CONSHDLR_NAME "/cutsasconss",
13661  "should the cumulative constraint create cuts as knapsack constraints?",
13662  &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13664  "constraints/" CONSHDLR_NAME "/sepaold",
13665  "shall old sepa algo be applied?",
13666  &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13667 
13669  "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13670  &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13671 
13672  /* presolving parameters */
13674  "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13675  &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13677  "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13678  &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13680  "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13681  &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13683  "constraints/" CONSHDLR_NAME "/presolpairwise",
13684  "should pairwise constraint comparison be performed in presolving?",
13685  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13687  "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13688  &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13689 
13691  "constraints/" CONSHDLR_NAME "/maxnodes",
13692  "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13693  &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13695  "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13696  &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13698  "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13699  &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13700 
13701  /* conflict analysis parameters */
13703  "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13704  &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13705 
13706  return SCIP_OKAY;
13707 }
13708 
13709 /** creates and captures a cumulative constraint */
13711  SCIP* scip, /**< SCIP data structure */
13712  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13713  const char* name, /**< name of constraint */
13714  int nvars, /**< number of variables (jobs) */
13715  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13716  int* durations, /**< array containing corresponding durations */
13717  int* demands, /**< array containing corresponding demands */
13718  int capacity, /**< available cumulative capacity */
13719  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13720  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13721  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13722  * Usually set to TRUE. */
13723  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13724  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13725  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13726  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13727  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13728  * Usually set to TRUE. */
13729  SCIP_Bool local, /**< is constraint only valid locally?
13730  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13731  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13732  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13733  * adds coefficients to this constraint. */
13734  SCIP_Bool dynamic, /**< is constraint subject to aging?
13735  * Usually set to FALSE. Set to TRUE for own cuts which
13736  * are seperated as constraints. */
13737  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13738  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13739  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13740  * if it may be moved to a more global node?
13741  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13742  )
13743 {
13744  SCIP_CONSHDLR* conshdlr;
13745  SCIP_CONSDATA* consdata;
13746 
13747  assert(scip != NULL);
13748 
13749  /* find the cumulative constraint handler */
13750  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13751  if( conshdlr == NULL )
13752  {
13753  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13754  return SCIP_PLUGINNOTFOUND;
13755  }
13756 
13757  SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13758 
13759  /* create constraint data */
13760  SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13761 
13762  /* create constraint */
13763  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13764  initial, separate, enforce, check, propagate,
13765  local, modifiable, dynamic, removable, stickingatnode) );
13766 
13767  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13768  {
13769  SCIP_CONSHDLRDATA* conshdlrdata;
13770 
13771  /* get event handler */
13772  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13773  assert(conshdlrdata != NULL);
13774  assert(conshdlrdata->eventhdlr != NULL);
13775 
13776  /* catch bound change events of variables */
13777  SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13778  }
13779 
13780  return SCIP_OKAY;
13781 }
13782 
13783 /** creates and captures a cumulative constraint
13784  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13785  * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13786  *
13787  * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13788  *
13789  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13790  */
13792  SCIP* scip, /**< SCIP data structure */
13793  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13794  const char* name, /**< name of constraint */
13795  int nvars, /**< number of variables (jobs) */
13796  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13797  int* durations, /**< array containing corresponding durations */
13798  int* demands, /**< array containing corresponding demands */
13799  int capacity /**< available cumulative capacity */
13800  )
13801 {
13802  assert(scip != NULL);
13803 
13804  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13805  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13806 
13807  return SCIP_OKAY;
13808 }
13809 
13810 /** set the left bound of the time axis to be considered (including hmin) */
13812  SCIP* scip, /**< SCIP data structure */
13813  SCIP_CONS* cons, /**< constraint data */
13814  int hmin /**< left bound of time axis to be considered */
13815  )
13816 {
13817  SCIP_CONSDATA* consdata;
13818  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13819  {
13820  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13821  return SCIP_INVALIDCALL;
13822  }
13823 
13824  consdata = SCIPconsGetData(cons);
13825  assert(consdata != NULL);
13826  assert(hmin >= 0);
13827  assert(hmin <= consdata->hmax);
13828 
13829  consdata->hmin = hmin;
13830 
13831  return SCIP_OKAY;
13832 }
13833 
13834 /** returns the left bound of the time axis to be considered */
13836  SCIP* scip, /**< SCIP data structure */
13837  SCIP_CONS* cons /**< constraint */
13838  )
13839 {
13840  SCIP_CONSDATA* consdata;
13841  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13842  {
13843  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13844  SCIPABORT();
13845  return 0; /*lint !e527*/
13846  }
13847 
13848  consdata = SCIPconsGetData(cons);
13849  assert(consdata != NULL);
13850 
13851  return consdata->hmin;
13852 }
13853 
13854 /** set the right bound of the time axis to be considered (not including hmax) */
13856  SCIP* scip, /**< SCIP data structure */
13857  SCIP_CONS* cons, /**< constraint data */
13858  int hmax /**< right bound of time axis to be considered */
13859  )
13860 {
13861  SCIP_CONSDATA* consdata;
13862  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13863  {
13864  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13865  SCIPABORT();
13866  return SCIP_INVALIDCALL; /*lint !e527*/
13867  }
13868 
13869  consdata = SCIPconsGetData(cons);
13870  assert(consdata != NULL);
13871  assert(hmax >= consdata->hmin);
13872 
13873  consdata->hmax = hmax;
13874 
13875  return SCIP_OKAY;
13876 }
13877 
13878 /** returns the right bound of the time axis to be considered */
13880  SCIP* scip, /**< SCIP data structure */
13881  SCIP_CONS* cons /**< constraint */
13882  )
13883 {
13884  SCIP_CONSDATA* consdata;
13885  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13886  {
13887  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13888  SCIPABORT();
13889  return 0; /*lint !e527*/
13890  }
13891 
13892  consdata = SCIPconsGetData(cons);
13893  assert(consdata != NULL);
13894 
13895  return consdata->hmax;
13896 }
13897 
13898 /** returns the activities of the cumulative constraint */
13900  SCIP* scip, /**< SCIP data structure */
13901  SCIP_CONS* cons /**< constraint data */
13902  )
13903 {
13904  SCIP_CONSDATA* consdata;
13905 
13906  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13907  {
13908  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13909  SCIPABORT();
13910  return NULL; /*lint !e527*/
13911  }
13912 
13913  consdata = SCIPconsGetData(cons);
13914  assert(consdata != NULL);
13915 
13916  return consdata->vars;
13917 }
13918 
13919 /** returns the activities of the cumulative constraint */
13921  SCIP* scip, /**< SCIP data structure */
13922  SCIP_CONS* cons /**< constraint data */
13923  )
13924 {
13925  SCIP_CONSDATA* consdata;
13926 
13927  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13928  {
13929  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13930  SCIPABORT();
13931  return -1; /*lint !e527*/
13932  }
13933 
13934  consdata = SCIPconsGetData(cons);
13935  assert(consdata != NULL);
13936 
13937  return consdata->nvars;
13938 }
13939 
13940 /** returns the capacity of the cumulative constraint */
13942  SCIP* scip, /**< SCIP data structure */
13943  SCIP_CONS* cons /**< constraint data */
13944  )
13945 {
13946  SCIP_CONSDATA* consdata;
13947 
13948  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13949  {
13950  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13951  SCIPABORT();
13952  return -1; /*lint !e527*/
13953  }
13954 
13955  consdata = SCIPconsGetData(cons);
13956  assert(consdata != NULL);
13957 
13958  return consdata->capacity;
13959 }
13960 
13961 /** returns the durations of the cumulative constraint */
13963  SCIP* scip, /**< SCIP data structure */
13964  SCIP_CONS* cons /**< constraint data */
13965  )
13966 {
13967  SCIP_CONSDATA* consdata;
13968 
13969  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13970  {
13971  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13972  SCIPABORT();
13973  return NULL; /*lint !e527*/
13974  }
13975 
13976  consdata = SCIPconsGetData(cons);
13977  assert(consdata != NULL);
13978 
13979  return consdata->durations;
13980 }
13981 
13982 /** returns the demands of the cumulative constraint */
13984  SCIP* scip, /**< SCIP data structure */
13985  SCIP_CONS* cons /**< constraint data */
13986  )
13987 {
13988  SCIP_CONSDATA* consdata;
13989 
13990  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13991  {
13992  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13993  SCIPABORT();
13994  return NULL; /*lint !e527*/
13995  }
13996 
13997  consdata = SCIPconsGetData(cons);
13998  assert(consdata != NULL);
13999 
14000  return consdata->demands;
14001 }
14002 
14003 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
14004  * given solution is satisfied
14005  */
14007  SCIP* scip, /**< SCIP data structure */
14008  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
14009  int nvars, /**< number of variables (jobs) */
14010  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14011  int* durations, /**< array containing corresponding durations */
14012  int* demands, /**< array containing corresponding demands */
14013  int capacity, /**< available cumulative capacity */
14014  int hmin, /**< left bound of time axis to be considered (including hmin) */
14015  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14016  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
14017  SCIP_CONS* cons, /**< constraint which is checked */
14018  SCIP_Bool printreason /**< should the reason for the violation be printed? */
14019  )
14020 {
14021  assert(scip != NULL);
14022  assert(violated != NULL);
14023 
14024  SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
14025  violated, cons, printreason) );
14026 
14027  return SCIP_OKAY;
14028 }
14029 
14030 /** normalize cumulative condition */
14032  SCIP* scip, /**< SCIP data structure */
14033  int nvars, /**< number of start time variables (activities) */
14034  SCIP_VAR** vars, /**< array of start time variables */
14035  int* durations, /**< array of durations */
14036  int* demands, /**< array of demands */
14037  int* capacity, /**< pointer to store the changed cumulative capacity */
14038  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
14039  int* nchgsides /**< pointer to count number of side changes */
14040  )
14041 {
14042  SCIP_CALL( normalizeCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14043  nchgcoefs, nchgsides) );
14044 
14045  return SCIP_OKAY;
14046 }
14047 
14048 /** searches for a time point within the cumulative condition were the cumulative condition can be split */
14050  SCIP* scip, /**< SCIP data structure */
14051  int nvars, /**< number of variables (jobs) */
14052  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14053  int* durations, /**< array containing corresponding durations */
14054  int* demands, /**< array containing corresponding demands */
14055  int capacity, /**< available cumulative capacity */
14056  int* hmin, /**< pointer to store the left bound of the effective horizon */
14057  int* hmax, /**< pointer to store the right bound of the effective horizon */
14058  int* split /**< point were the cumulative condition can be split */
14059  )
14060 {
14061  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14062  hmin, hmax, split) );
14063 
14064  return SCIP_OKAY;
14065 }
14066 
14067 /** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
14069  SCIP* scip, /**< SCIP data structure */
14070  int nvars, /**< number of start time variables (activities) */
14071  SCIP_VAR** vars, /**< array of start time variables */
14072  int* durations, /**< array of durations */
14073  int hmin, /**< left bound of time axis to be considered */
14074  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14075  SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
14076  SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
14077  SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
14078  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
14079  int* nfixedvars, /**< pointer to store the number of fixed variables */
14080  int* nchgsides, /**< pointer to store the number of changed sides */
14081  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
14082  )
14083 {
14084  if( nvars <= 1 )
14085  return SCIP_OKAY;
14086 
14087  /* presolve constraint form the earlier start time point of view */
14088  SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14089  irrelevants, nfixedvars, nchgsides, cutoff) );
14090 
14091  /* presolve constraint form the latest completion time point of view */
14092  SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14093  irrelevants, nfixedvars, nchgsides, cutoff) );
14094 
14095  return SCIP_OKAY;
14096 }
14097 
14098 /** propagate the given cumulative condition */
14100  SCIP* scip, /**< SCIP data structure */
14101  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
14102  int nvars, /**< number of variables (jobs) */
14103  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14104  int* durations, /**< array containing corresponding durations */
14105  int* demands, /**< array containing corresponding demands */
14106  int capacity, /**< available cumulative capacity */
14107  int hmin, /**< left bound of time axis to be considered (including hmin) */
14108  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14109  SCIP_CONS* cons, /**< constraint which gets propagated */
14110  int* nchgbds, /**< pointer to store the number of variable bound changes */
14111  SCIP_Bool* initialized, /**< was conflict analysis initialized */
14112  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14113  SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14114  )
14115 {
14116  SCIP_CONSHDLR* conshdlr;
14117  SCIP_CONSHDLRDATA* conshdlrdata;
14118  SCIP_Bool redundant;
14119 
14120  assert(scip != NULL);
14121  assert(cons != NULL);
14122  assert(initialized != NULL);
14123  assert(*initialized == FALSE);
14124  assert(cutoff != NULL);
14125  assert(*cutoff == FALSE);
14126 
14127  /* find the cumulative constraint handler */
14128  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14129  if( conshdlr == NULL )
14130  {
14131  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14132  return SCIP_PLUGINNOTFOUND;
14133  }
14134 
14135  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14136  assert(conshdlrdata != NULL);
14137 
14138  redundant = FALSE;
14139 
14140  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14141  nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14142  nchgbds, &redundant, initialized, explanation, cutoff) );
14143 
14144  return SCIP_OKAY;
14145 }
14146 
14147 /** resolve propagation w.r.t. the cumulative condition */
14149  SCIP* scip, /**< SCIP data structure */
14150  int nvars, /**< number of start time variables (activities) */
14151  SCIP_VAR** vars, /**< array of start time variables */
14152  int* durations, /**< array of durations */
14153  int* demands, /**< array of demands */
14154  int capacity, /**< cumulative capacity */
14155  int hmin, /**< left bound of time axis to be considered (including hmin) */
14156  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14157  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14158  int inferinfo, /**< the user information */
14159  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14160  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14161  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14162  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14163  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14164  )
14165 {
14166  SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14167  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14168 
14169  return SCIP_OKAY;
14170 }
14171 
14172 /** this method visualizes the cumulative structure in GML format */
14174  SCIP* scip, /**< SCIP data structure */
14175  SCIP_CONS* cons /**< cumulative constraint */
14176  )
14177 {
14178  SCIP_CONSDATA* consdata;
14179  SCIP_HASHTABLE* vars;
14180  FILE* file;
14181  SCIP_VAR* var;
14182  char filename[SCIP_MAXSTRLEN];
14183  int nvars;
14184  int v;
14185 
14186  SCIP_RETCODE retcode = SCIP_OKAY;
14187 
14188  /* open file */
14189  (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14190  file = fopen(filename, "w");
14191 
14192  /* check if the file was open */
14193  if( file == NULL )
14194  {
14195  SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14196  SCIPprintSysError(filename);
14197  return SCIP_FILECREATEERROR;
14198  }
14199 
14200  consdata = SCIPconsGetData(cons);
14201  assert(consdata != NULL);
14202 
14203  nvars = consdata->nvars;
14204 
14205  SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
14206  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
14207 
14208  /* create opening of the GML format */
14209  SCIPgmlWriteOpening(file, TRUE);
14210 
14211  for( v = 0; v < nvars; ++v )
14212  {
14213  char color[SCIP_MAXSTRLEN];
14214 
14215  var = consdata->vars[v];
14216  assert(var != NULL);
14217 
14218  SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
14219 
14220  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14221  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14222  else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14223  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14224  else
14225  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14226 
14227  SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14228  }
14229 
14230  for( v = 0; v < nvars; ++v )
14231  {
14232  SCIP_VAR** vbdvars;
14233  int nvbdvars;
14234  int b;
14235 
14236  var = consdata->vars[v];
14237  assert(var != NULL);
14238 
14239  vbdvars = SCIPvarGetVlbVars(var);
14240  nvbdvars = SCIPvarGetNVlbs(var);
14241 
14242  for( b = 0; b < nvbdvars; ++b )
14243  {
14244  if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14245  {
14246  SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14247  }
14248  }
14249 
14250 #if 0
14251  vbdvars = SCIPvarGetVubVars(var);
14252  nvbdvars = SCIPvarGetNVubs(var);
14253 
14254  for( b = 0; b < nvbdvars; ++b )
14255  {
14256  if( SCIPhashtableExists(vars, vbdvars[b]) )
14257  {
14258  SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14259  }
14260  }
14261 #endif
14262  }
14263 
14264  /* create closing of the GML format */
14265  SCIPgmlWriteClosing(file);
14266 TERMINATE:
14267  /* close file */
14268  fclose(file);
14269 
14270  SCIPhashtableFree(&vars);
14271 
14272  return retcode;
14273 }
14274 
14275 /** sets method to solve an individual cumulative condition */
14277  SCIP* scip, /**< SCIP data structure */
14278  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14279  )
14280 {
14281  SCIP_CONSHDLR* conshdlr;
14282  SCIP_CONSHDLRDATA* conshdlrdata;
14283 
14284  /* find the cumulative constraint handler */
14285  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14286  if( conshdlr == NULL )
14287  {
14288  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14289  return SCIP_PLUGINNOTFOUND;
14290  }
14291 
14292  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14293  assert(conshdlrdata != NULL);
14294 
14295  conshdlrdata->solveCumulative = solveCumulative;
14296 
14297  return SCIP_OKAY;
14298 }
14299 
14300 /** solves given cumulative condition as independent sub problem
14301  *
14302  * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14303  * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14304  * solver was interrupted.
14305  */
14307  SCIP* scip, /**< SCIP data structure */
14308  int njobs, /**< number of jobs (activities) */
14309  SCIP_Real* ests, /**< array with the earlier start time for each job */
14310  SCIP_Real* lsts, /**< array with the latest start time for each job */
14311  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14312  int* durations, /**< array of durations */
14313  int* demands, /**< array of demands */
14314  int capacity, /**< cumulative capacity */
14315  int hmin, /**< left bound of time axis to be considered (including hmin) */
14316  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14317  SCIP_Real timelimit, /**< time limit for solving in seconds */
14318  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14319  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14320  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14321  SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14322  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14323  SCIP_Bool* error /**< pointer to store if an error occurred */
14324  )
14325 {
14326  SCIP_CONSHDLR* conshdlr;
14327  SCIP_CONSHDLRDATA* conshdlrdata;
14328 
14329  (*solved) = TRUE;
14330  (*infeasible) = FALSE;
14331  (*unbounded) = FALSE;
14332  (*error) = FALSE;
14333 
14334  if( njobs == 0 )
14335  return SCIP_OKAY;
14336 
14337  /* find the cumulative constraint handler */
14338  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14339  if( conshdlr == NULL )
14340  {
14341  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14342  (*error) = TRUE;
14343  return SCIP_PLUGINNOTFOUND;
14344  }
14345 
14346  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14347  assert(conshdlrdata != NULL);
14348 
14349  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14350  if( timelimit > 0.0 && memorylimit > 10 )
14351  {
14352  SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14353  hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14354  }
14355 
14356  return SCIP_OKAY;
14357 }
14358 
14359 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14360  * completion time
14361  */
14363  SCIP* scip, /**< SCIP data structure */
14364  SCIP_PROFILE* profile, /**< resource profile */
14365  int nvars, /**< number of variables (jobs) */
14366  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14367  int* durations, /**< array containing corresponding durations */
14368  int* demands /**< array containing corresponding demands */
14369  )
14370 {
14371  SCIP_VAR* var;
14372  SCIP_HASHMAP* addedvars;
14373  int* copydemands;
14374  int* perm;
14375  int duration;
14376  int impliedest;
14377  int est;
14378  int impliedlct;
14379  int lct;
14380  int v;
14381 
14382  /* create hash map for variables which are added, mapping to their duration */
14383  SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
14384 
14385  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14386  SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14387 
14388  /* sort variables w.r.t. job demands */
14389  for( v = 0; v < nvars; ++v )
14390  {
14391  copydemands[v] = demands[v];
14392  perm[v] = v;
14393  }
14394  SCIPsortDownIntInt(copydemands, perm, nvars);
14395 
14396  /* add each job with its earliest start and latest completion time into the resource profile */
14397  for( v = 0; v < nvars; ++v )
14398  {
14399  int idx;
14400 
14401  idx = perm[v];
14402  assert(idx >= 0 && idx < nvars);
14403 
14404  var = vars[idx];
14405  assert(var != NULL);
14406 
14407  duration = durations[idx];
14408  assert(duration > 0);
14409 
14410  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
14411  SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14412 
14413  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14414  SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14415 
14416  if( impliedest < impliedlct )
14417  {
14418  SCIP_Bool infeasible;
14419  int pos;
14420 
14421  SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14422  assert(!infeasible);
14423  assert(pos == -1);
14424  }
14425 
14426  if( est == impliedest && lct == impliedlct )
14427  {
14428  SCIP_CALL( SCIPhashmapInsertInt(addedvars, (void*)var, duration) );
14429  }
14430  }
14431 
14432  SCIPfreeBufferArray(scip, &copydemands);
14433  SCIPfreeBufferArray(scip, &perm);
14434 
14435  SCIPhashmapFree(&addedvars);
14436 
14437  return SCIP_OKAY;
14438 }
14439 
14440 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */
14441 int SCIPcomputeHmin(
14442  SCIP* scip, /**< SCIP data structure */
14443  SCIP_PROFILE* profile, /**< worst case resource profile */
14444  int capacity /**< capacity to check */
14445  )
14446 {
14447  int* timepoints;
14448  int* loads;
14449  int ntimepoints;
14450  int t;
14451 
14452  ntimepoints = SCIPprofileGetNTimepoints(profile);
14453  timepoints = SCIPprofileGetTimepoints(profile);
14454  loads = SCIPprofileGetLoads(profile);
14455 
14456  /* find first time point which potentially violates the capacity restriction */
14457  for( t = 0; t < ntimepoints - 1; ++t )
14458  {
14459  /* check if the time point exceed w.r.t. worst case profile the capacity */
14460  if( loads[t] > capacity )
14461  {
14462  assert(t == 0 || loads[t-1] <= capacity);
14463  return timepoints[t];
14464  }
14465  }
14466 
14467  return INT_MAX;
14468 }
14469 
14470 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity is satisfied for sure */
14471 int SCIPcomputeHmax(
14472  SCIP* scip, /**< SCIP data structure */
14473  SCIP_PROFILE* profile, /**< worst case profile */
14474  int capacity /**< capacity to check */
14475  )
14476 {
14477  int* timepoints;
14478  int* loads;
14479  int ntimepoints;
14480  int t;
14481 
14482  ntimepoints = SCIPprofileGetNTimepoints(profile);
14483  timepoints = SCIPprofileGetTimepoints(profile);
14484  loads = SCIPprofileGetLoads(profile);
14485 
14486  /* find last time point which potentially violates the capacity restriction */
14487  for( t = ntimepoints - 1; t >= 0; --t )
14488  {
14489  /* check if at time point t the worst case resource profile exceeds the capacity */
14490  if( loads[t] > capacity )
14491  {
14492  assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14493  return timepoints[t+1];
14494  }
14495  }
14496 
14497  return INT_MIN;
14498 }
14499 
14500 /**@} */
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
static SCIP_RETCODE consdataCatchEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
#define CONSHDLR_SEPAPRIORITY
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4221
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:86
SCIP_RETCODE SCIPcreateConsBasicSetpart(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
Definition: cons_setppc.c:9101
SCIP_BTNODE * SCIPbtnodeGetRightchild(SCIP_BTNODE *node)
Definition: misc.c:8385
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_EXPORT SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16880
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_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
static SCIP_DECL_CONSCOPY(consCopyCumulative)
#define NULL
Definition: def.h:253
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:686
enum TCLIQUE_Status TCLIQUE_STATUS
Definition: tclique.h:59
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:585
static TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
#define DEFAULT_TTINFER
#define CONSHDLR_PROPFREQ
static int computeEnergyContribution(SCIP_BTNODE *node)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:80
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2364
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip_branch.c:654
static SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:876
static SCIP_RETCODE consdataDropAllEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static PROPRULE inferInfoGetProprule(INFERINFO inferinfo)
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:1994
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 SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:452
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5121
static SCIP_RETCODE computeMinDistance(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int source, int sink, int *naddconss)
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:933
SCIP_RETCODE SCIPaddVarVlb(SCIP *scip, SCIP_VAR *var, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconstant, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip_var.c:6573
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8315
struct TCLIQUE_Graph TCLIQUE_GRAPH
Definition: tclique.h:40
static INFERINFO intToInferInfo(int i)
SCIP_EXPORT int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3241
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:307
SCIP_BTNODE * SCIPbtnodeGetLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8375
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:466
int SCIPprofileGetLoad(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6618
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_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8275
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:165
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4200
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2476
static void addEndingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *endtimes, int *endindices, int *freecapacity, int *idx, int nvars)
#define SCIP_MAXSTRLEN
Definition: def.h:274
#define DEFAULT_MAXNODES
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:1483
SCIP_RETCODE SCIPcreateConsBasicCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity)
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)
static SCIP_RETCODE constraintNonOverlappingGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:815
static long bound
SCIP_EXPORT void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
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)
#define CONSHDLR_NAME
#define SCIP_CALL_FINALLY(x, y)
Definition: def.h:407
SCIP_VAR ** SCIPgetVarsCumulative(SCIP *scip, SCIP_CONS *cons)
#define CONSHDLR_PROP_TIMING
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1352
SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_setppc.c:9232
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5237
static SCIP_RETCODE createDisjuctiveCons(SCIP *scip, SCIP_CONS *cons, int *naddconss)
#define CONSHDLR_CHECKPRIORITY
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2031
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)
static void updateKeyOnTrace(SCIP_BTNODE *node, SCIP_Real key)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:8690
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:769
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)
SCIP_Bool SCIPbtnodeIsLeaf(SCIP_BTNODE *node)
Definition: misc.c:8425
static SCIP_RETCODE computePeak(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *timepoint)
SCIP_BTNODE * SCIPbtnodeGetParent(SCIP_BTNODE *node)
Definition: misc.c:8365
static SCIP_Longint computeCoreWithInterval(int begin, int end, int ect, int lst)
static void transitiveClosure(SCIP_Bool **adjmatrix, int *ninarcs, int *noutarcs, int nnodes)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5530
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition: scip_var.c:184
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3009
SCIP_RETCODE SCIPbtCreate(SCIP_BT **tree, BMS_BLKMEM *blkmem)
Definition: misc.c:8527
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:314
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3037
static SCIP_Bool isConsIndependently(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1987
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8137
static SCIP_RETCODE applyAlternativeBoundsFixing(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, int *nfixedvars, SCIP_Bool *cutoff)
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:359
static SCIP_DECL_SORTPTRCOMP(compNodeEst)
#define FALSE
Definition: def.h:73
void SCIPstrCopySection(const char *str, char startchar, char endchar, char *token, int size, char **endptr)
Definition: misc.c:10394
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_EXPORT SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17200
static SCIP_RETCODE consdataFreeRows(SCIP *scip, SCIP_CONSDATA **consdata)
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)
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)
SCIP_EXPORT SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16903
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:72
#define SCIPdebug(x)
Definition: pub_message.h:74
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
enum Proprule PROPRULE
static void subtractStartingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *starttimes, int *startindices, int *freecapacity, int *idx, int nvars)
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3470
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:523
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8245
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
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)
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)
static SCIP_RETCODE strengthenVarbounds(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *naddconss)
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:562
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2535
static SCIP_RETCODE getNodeIdx(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_VAR *var, int *idx)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3078
SCIP_EXPORT SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17025
static void conshdlrdataFree(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata)
#define DEFAULT_LOCALCUTS
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:47
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:95
SCIP_Longint SCIPgetMemUsed(SCIP *scip)
Definition: scip_mem.c:90
static SCIP_RETCODE deleteLambdaLeaf(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
#define SCIPdebugMessage
Definition: pub_message.h:77
#define CONSHDLR_DELAYPROP
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1502
static SCIP_RETCODE separateCoverCutsCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
#define DEFAULT_USEBINVARS
SCIP_EXPORT SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16857
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip_cons.c:1232
SCIP_RETCODE SCIPsetSubscipsOff(SCIP *scip, SCIP_Bool quiet)
Definition: scip_param.c:891
static TCLIQUE_ISEDGE(tcliqueIsedgeClique)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:119
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)
#define DEFAULT_COEFTIGHTENING
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:524
static SCIP_RETCODE createNodedata(SCIP *scip, SCIP_NODEDATA **nodedata)
#define SCIP_LONGINT_MAX
Definition: def.h:150
SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:123
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:135
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip_cons.c:1257
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:838
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:78
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
#define DEFAULT_TTEFCHECK
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 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 SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:500
SCIP_RETCODE SCIPsetHmaxCumulative(SCIP *scip, SCIP_CONS *cons, int hmax)
#define SCIPdebugMsgPrint
Definition: scip_message.h:70
#define SCIPdebugMsg
Definition: scip_message.h:69
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2005
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
void SCIPprofilePrint(SCIP_PROFILE *profile, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: misc.c:6544
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4291
SCIP_EXPORT void SCIPsortInt(int *intarray, int len)
static SCIP_DECL_CONSPRESOL(consPresolCumulative)
SCIP_EXPORT SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17556
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:558
#define DEFAULT_NORMALIZE
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
static SCIP_RETCODE deleteTrivilCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:356
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip_cons.c:1460
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)
void * SCIPbtnodeGetData(SCIP_BTNODE *node)
Definition: misc.c:8355
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)
enum Proprule PROPRULE
static SCIP_RETCODE adjustOversizedJobBounds(SCIP *scip, SCIP_CONSDATA *consdata, int pos, int *nchgbds, int *naddconss, SCIP_Bool *cutoff)
SCIP_Bool SCIPbtnodeIsLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8435
void SCIPgmlWriteOpening(FILE *file, SCIP_Bool directed)
Definition: misc.c:671
void SCIPgmlWriteArc(FILE *file, unsigned int source, unsigned int target, const char *label, const char *color)
Definition: misc.c:627
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:2113
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:264
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
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2838
#define MIN3(x, y, z)
Definition: def.h:228
static void createSortedEventpointsSol(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices)
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17177
int SCIPgetNVarsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE conshdlrdataCreate(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
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)
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition: scip_param.c:612
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3098
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip_copy.c:672
SCIP_RETCODE SCIPsplitCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
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)
SCIP_EXPORT SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:16939
static SCIP_RETCODE separateConsBinaryRepresentation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
static SCIP_RETCODE findPrecedenceConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
static SCIP_DECL_CONSCHECK(consCheckCumulative)
static SCIP_Longint computeTotalEnergy(int *durations, int *demands, int njobs)
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3240
static SCIP_RETCODE tightenLbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int ect, int lct, int begin, int end, SCIP_Longint energy, int *bestlb, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_RETCODE getHighestCapacityUsage(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, int *bestcapacity)
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:92
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8542
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)
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip_general.c:282
int SCIPprofileGetNTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6576
Constraint handler for knapsack constraints of the form , x binary and .
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10571
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1479
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_EXPORT const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16738
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_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 SCIPerrorMessage
Definition: pub_message.h:45
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10364
static SCIP_RETCODE projectVbd(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph)
static SCIP_RETCODE createTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
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_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1406
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE collectBinaryVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***vars, int **coefs, int *nvars, int *startindices, int curtime, int nstarted, int nfinished)
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1942
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:109
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
int SCIPgetHmaxCumulative(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:124
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:47
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
static void traceLambdaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
SCIP_EXPORT SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17608
SCIP_EXPORT void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
static SCIP_RETCODE computeEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss, int *nchgsides)
static int computeEstOmegaset(SCIP *scip, int duration, int demand, int capacity, int est, int lct, int energy)
void SCIPbtnodeFree(SCIP_BT *tree, SCIP_BTNODE **node)
Definition: misc.c:8310
SCIP_Bool SCIPexistsConsLinking(SCIP *scip, SCIP_VAR *intvar)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
static SCIP_RETCODE branch(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_RESULT *result)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:155
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:87
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 SCIPincludeConshdlrCumulative(SCIP *scip)
#define CONSHDLR_MAXPREROUNDS
static SCIP_RETCODE createCoverCuts(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:476
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss, SCIP_Bool *infeasible)
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8106
static SCIP_RETCODE solveCumulative(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool local, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Longint maxnodes, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *error)
#define SCIP_CALL(x)
Definition: def.h:365
SCIP_EXPORT int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17586
void SCIPswapInts(int *value1, int *value2)
Definition: misc.c:9865
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:631
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)
SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1033
SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
Definition: scip_param.c:670
#define SCIPstatisticPrintf
Definition: pub_message.h:107
static TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
Definition: grphload.c:88
#define DEFAULT_PRESOLPAIRWISE
#define DEFAULT_DETECTDISJUNCTIVE
static SCIP_DECL_CONSFREE(consFreeCumulative)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:51
SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1074
SCIP_EXPORT void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:106
static SCIP_RETCODE consCapacityConstraintsFinder(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
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)
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1748
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip_param.c:297
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8345
constraint handler for linking binary variables to an integer variable
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:111
#define SCIP_UNKNOWN
Definition: def.h:185
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:129
SCIP_Real SCIPinfinity(SCIP *scip)
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)
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip_cons.c:219
static void traceThetaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4376
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2163
SCIP_EXPORT void SCIPsortDownIntIntInt(int *intarray1, int *intarray2, int *intarray3, int len)
SCIP_CONS * SCIPgetConsLinking(SCIP *scip, SCIP_VAR *intvar)
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:637
#define SCIP_Bool
Definition: def.h:70
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)
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:390
static SCIP_DECL_CONSPROP(consPropCumulative)
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1207
#define DEFAULT_DUALPRESOLVE
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2891
SCIP_Bool SCIPbtnodeIsRoot(SCIP_BTNODE *node)
Definition: misc.c:8415
SCIP_EXPORT void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
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)
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:331
int SCIPgetNCheckConss(SCIP *scip)
Definition: scip_prob.c:3179
SCIP_EXPORT SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17362
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2472
#define DEFAULT_USECOVERCUTS
SCIP_RETCODE SCIPprofileDeleteCore(SCIP_PROFILE *profile, int left, int right, int demand)
Definition: misc.c:6809
static void freeNodedata(SCIP *scip, SCIP_NODEDATA **nodedata)
static SCIP_DECL_EVENTEXEC(eventExecCumulative)
int SCIPprofileGetTime(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6606
void SCIPbtSetRoot(SCIP_BT *tree, SCIP_BTNODE *root)
Definition: misc.c:8651
SCIP_Bool SCIPprofileFindLeft(SCIP_PROFILE *profile, int timepoint, int *pos)
Definition: misc.c:6632
#define SCIP_DECL_CONSEXITPRE(x)
Definition: type_cons.h:165
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:90
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4211
SCIP_Bool SCIPallowDualReds(SCIP *scip)
Definition: scip_var.c:8506
SCIP_RETCODE SCIPsetEmphasis(SCIP *scip, SCIP_PARAMEMPHASIS paramemphasis, SCIP_Bool quiet)
Definition: scip_param.c:869
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip_var.c:104
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)
#define MIN(x, y)
Definition: def.h:223
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1268
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)
void SCIPgmlWriteClosing(FILE *file)
Definition: misc.c:687
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5317
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8385
SCIP_RETCODE SCIPbtnodeCreate(SCIP_BT *tree, SCIP_BTNODE **node, void *dataptr)
Definition: misc.c:8246
SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
SCIP_Bool SCIPbtIsEmpty(SCIP_BT *tree)
Definition: misc.c:8628
#define SCIP_PRESOLTIMING_ALWAYS
Definition: type_timing.h:49
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:124
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8255
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8180
int * SCIPprofileGetLoads(SCIP_PROFILE *profile)
Definition: misc.c:6596
SCIP_BTNODE * SCIPbtGetRoot(SCIP_BT *tree)
Definition: misc.c:8638
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)
int * SCIPgetValsLinking(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
static SCIP_RETCODE consdataDeletePos(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_CONS *cons, int pos)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1667
#define CONSHDLR_NEEDSCONS
static SCIP_RETCODE computeImpliedEst(SCIP *scip, SCIP_VAR *var, SCIP_HASHMAP *addedvars, int *est)
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8335
static SCIP_RETCODE tightenCoefs(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs)
static SCIP_DECL_SORTINDCOMP(consdataCompVar)
Proprule
SCIP_EXPORT SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17408
#define DEFAULT_FILLBRANCHCANDS
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:94
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:9891
static SCIP_Bool checkDemands(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2130
SCIP_EXPORT int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3184
#define DEFAULT_DETECTVARBOUNDS
static SCIP_RETCODE tightenUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int lst, int lct, int begin, int end, SCIP_Longint energy, int *bestub, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
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)
int SCIPconvertRealToInt(SCIP *scip, SCIP_Real real)
static SCIP_RETCODE setupAndSolveCumulativeSubscip(SCIP *subscip, SCIP_Real *objvals, int *durations, int *demands, int njobs, int capacity, int hmin, int hmax, SCIP_Longint maxnodes, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *solved, SCIP_Bool *error)
SCIP_Real * r
Definition: circlepacking.c:50
SCIP_RETCODE SCIPpresolveCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
SCIP_EXPORT SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17418
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip_param.c:554
static void createSortedEventpoints(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices, SCIP_Bool local)
#define SCIP_LONGINT_FORMAT
Definition: def.h:156
SCIP_VAR ** b
Definition: circlepacking.c:56
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:220
SCIP_RETCODE SCIPsetHminCumulative(SCIP *scip, SCIP_CONS *cons, int hmin)
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5417
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:121
static SCIP_RETCODE insertThetanode(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node, SCIP_NODEDATA **nodedatas, int *nnodedatas)
#define MAX(x, y)
Definition: def.h:222
#define CONSHDLR_SEPAFREQ
int SCIPgetCapacityCumulative(SCIP *scip, SCIP_CONS *cons)
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)
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)
static SCIP_DECL_CONSPRINT(consPrintCumulative)
static SCIP_RETCODE consdataCollectLinkingCons(SCIP *scip, SCIP_CONSDATA *consdata)
static SCIP_RETCODE initializeDurations(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8265
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnvelop(SCIP_BTNODE *node)
SCIP_RETCODE SCIPtransformConss(SCIP *scip, int nconss, SCIP_CONS **conss, SCIP_CONS **transconss)
Definition: scip_cons.c:1561
int * SCIPprofileGetTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6586
void SCIPbtnodeSetParent(SCIP_BTNODE *node, SCIP_BTNODE *parent)
Definition: misc.c:8488
static SCIP_RETCODE constructIncompatibilityGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
SCIP_EXPORT SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17352
static SCIP_RETCODE moveNodeToLambda(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
SCIP_EXPORT SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17566
#define DEFAULT_CUTSASCONSS
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1539
static void collectThetaSubtree(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
static SCIP_RETCODE separateConsOnIntegerVariables(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool lower, SCIP_Bool *separated, SCIP_Bool *cutoff)
void SCIPbtnodeSetLeftchild(SCIP_BTNODE *node, SCIP_BTNODE *left)
Definition: misc.c:8502
void SCIPprofileFree(SCIP_PROFILE **profile)
Definition: misc.c:6528
SCIP_EXPORT 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)
SCIP_EXPORT SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17576
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)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10263
void SCIPbtnodeSetRightchild(SCIP_BTNODE *node, SCIP_BTNODE *right)
Definition: misc.c:8516
static SCIP_RETCODE normalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2925
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8076
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1251
SCIP_RETCODE SCIPcreateWorstCaseProfile(SCIP *scip, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands)
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8205
#define SCIPstatistic(x)
Definition: pub_message.h:101
int * SCIPgetDemandsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
#define SCIP_Real
Definition: def.h:164
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)
static SCIP_DECL_CONSTRANS(consTransCumulative)
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:386
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8096
SCIP_Bool SCIPbtnodeIsRightchild(SCIP_BTNODE *node)
Definition: misc.c:8453
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)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define DEFAULT_EFCHECK
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIP_INVALID
Definition: def.h:184
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1848
#define EVENTHDLR_DESC
#define DEFAULT_TTEFINFER
void SCIPprintSysError(const char *message)
Definition: misc.c:10172
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:149
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition: scip_param.c:438
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8355
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4191
static SCIP_RETCODE detectRedundantConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, int *naddconss)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip_var.c:1796
static SCIP_RETCODE varMayRoundUp(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:344
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_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:101
SCIP_EXPORT int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17045
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2765
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:50
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
static SCIP_RETCODE createCapacityRestriction(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool cutsasconss)
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:98
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_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
static SCIP_Bool impliesVlbPrecedenceCondition(SCIP *scip, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconst, int duration)
#define DEFAULT_DISJUNCTIVE
int SCIPcomputeHmax(SCIP *scip, SCIP_PROFILE *profile, int capacity)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:120
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
#define DEFAULT_USEBDWIDENING
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:314
SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
Definition: scip_mem.c:116
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:198
static SCIP_RETCODE tightenCapacity(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
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)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1109
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition: scip_var.c:8305
void SCIPgmlWriteNode(FILE *file, unsigned int id, const char *label, const char *nodetype, const char *fillcolor, const char *bordercolor)
Definition: misc.c:485
int TCLIQUE_WEIGHT
Definition: tclique.h:39
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:355
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:792
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)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:265
SCIP_EXPORT SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:16949
#define SCIPABORT()
Definition: def.h:337
static SCIP_DECL_CONSDELETE(consDeleteCumulative)
void SCIPbtFree(SCIP_BT **tree)
Definition: misc.c:8546
SCIP_RETCODE SCIPvisualizeConsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPORT SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17618
default SCIP plugins
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnergy(SCIP_BTNODE *node)
SCIP_RETCODE SCIPprofileInsertCore(SCIP_PROFILE *profile, int left, int right, int demand, int *pos, SCIP_Bool *infeasible)
Definition: misc.c:6779
static SCIP_DECL_CONSSEPALP(consSepalpCumulative)
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2304
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8295
SCIP_EXPORT SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17598
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *violated, SCIP_Bool printreason)
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3256
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip_param.c:496
SCIP_RETCODE SCIPprofileCreate(SCIP_PROFILE **profile, int capacity)
Definition: misc.c:6514
static SCIP_RETCODE createCapacityRestrictionIntvars(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
Definition: scip_prob.c:166
SCIP_RETCODE SCIPgetBinvarsLinking(SCIP *scip, SCIP_CONS *cons, SCIP_VAR ***binvars, int *nbinvars)
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:608
static int inferInfoToInt(INFERINFO inferinfo)
static TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
SCIP_RETCODE SCIPsetSolveCumulative(SCIP *scip, SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)))
SCIP_EXPORT int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17544
static SCIP_DECL_CONSRESPROP(consRespropCumulative)
SCIP_EXPORT int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17035
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8325
static SCIP_RETCODE varMayRoundDown(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
#define CONSHDLR_ENFOPRIORITY
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip_solve.c:3425
SCIP_EXPORT int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11436
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
static SCIP_Bool impliesVubPrecedenceCondition(SCIP *scip, SCIP_VAR *var, SCIP_Real vubcoef, SCIP_Real vubconst, int duration)
int SCIPgetNRuns(SCIP *scip)
#define DEFAULT_SEPAOLD