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-2017 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_cumulative.c
17  * @brief constraint handler for cumulative constraints
18  * @author Timo Berthold
19  * @author Stefan Heinz
20  * @author Jens Schulz
21  *
22  * Given:
23  * - a set of jobs, represented by their integer start time variables \f$S_j\f$, their array of processing times \f$p_j\f$ and of
24  * their demands \f$d_j\f$.
25  * - an integer resource capacity \f$C\f$
26  *
27  * The cumulative constraint ensures that for each point in time \f$t\f$ \f$\sum_{j: S_j \leq t < S_j + p_j} d_j \leq C\f$ holds.
28  *
29  * Separation:
30  * - can be done using binary start time model, see Pritskers, Watters and Wolfe
31  * - or by just separating relatively weak cuts on the integer start time variables
32  *
33  * Propagation:
34  * - time tabling, Klein & Scholl (1999)
35  * - Edge-finding from Petr Vilim, adjusted and simplified for dynamic repropagation
36  * (2009)
37  * - energetic reasoning, see Baptiste, Le Pape, Nuijten (2001)
38  *
39  */
40 
41 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
42 
43 #include <assert.h>
44 #include <string.h>
45 
46 #include "tclique/tclique.h"
47 #include "scip/cons_cumulative.h"
48 #include "scip/cons_linking.h"
49 #include "scip/cons_knapsack.h"
50 #include "scip/scipdefplugins.h"
51 
52 /**@name Constraint handler properties
53  *
54  * @{
55  */
56 
57 /* constraint handler properties */
58 #define CONSHDLR_NAME "cumulative"
59 #define CONSHDLR_DESC "cumulative constraint handler"
60 #define CONSHDLR_SEPAPRIORITY 2100000 /**< priority of the constraint handler for separation */
61 #define CONSHDLR_ENFOPRIORITY -2040000 /**< priority of the constraint handler for constraint enforcing */
62 #define CONSHDLR_CHECKPRIORITY -3030000 /**< priority of the constraint handler for checking feasibility */
63 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
64 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
65 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
66  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
67 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
68 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
69 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
70 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
71 
72 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
73 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
74 
75 /**@} */
76 
77 /**@name Default parameter values
78  *
79  * @{
80  */
81 
82 /* default parameter values */
83 
84 /* separation */
85 #define DEFAULT_USEBINVARS FALSE /**< should the binary representation be used? */
86 #define DEFAULT_LOCALCUTS FALSE /**< should cuts be added only locally? */
87 #define DEFAULT_USECOVERCUTS TRUE /**< should covering cuts be added? */
88 #define DEFAULT_CUTSASCONSS TRUE /**< should the cuts be created as knapsack constraints? */
89 #define DEFAULT_SEPAOLD TRUE /**< shall old sepa algo be applied? */
90 
91 /* propagation */
92 #define DEFAULT_TTINFER TRUE /**< should time-table (core-times) propagator be used to infer bounds? */
93 #define DEFAULT_EFCHECK FALSE /**< should edge-finding be used to detect an overload? */
94 #define DEFAULT_EFINFER FALSE /**< should edge-finding be used to infer bounds? */
95 #define DEFAULT_USEADJUSTEDJOBS FALSE /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
96 #define DEFAULT_TTEFCHECK TRUE /**< should time-table edge-finding be used to detect an overload? */
97 #define DEFAULT_TTEFINFER TRUE /**< should time-table edge-finding be used to infer bounds? */
98 
99 /* presolving */
100 #define DEFAULT_DUALPRESOLVE TRUE /**< should dual presolving be applied? */
101 #define DEFAULT_COEFTIGHTENING FALSE /**< should coeffisient tightening be applied? */
102 #define DEFAULT_NORMALIZE TRUE /**< should demands and capacity be normalized? */
103 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
104 #define DEFAULT_DISJUNCTIVE TRUE /**< extract disjunctive constraints? */
105 #define DEFAULT_DETECTDISJUNCTIVE TRUE /**< search for conflict set via maximal cliques to detect disjunctive constraints */
106 #define DEFAULT_DETECTVARBOUNDS TRUE /**< search for conflict set via maximal cliques to detect variable bound constraints */
107 #define DEFAULT_MAXNODES 10000LL /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
109 /* enforcement */
110 #define DEFAULT_FILLBRANCHCANDS FALSE /**< should branching candidates be added to storage? */
112 /* conflict analysis */
113 #define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used during conflict analysis? */
115 /**@} */
116 
117 /**@name Event handler properties
118  *
119  * @{
120  */
121 
122 #define EVENTHDLR_NAME "cumulative"
123 #define EVENTHDLR_DESC "bound change event handler for cumulative constraints"
125 /**@} */
126 
127 /*
128  * Data structures
129  */
130 
131 /** constraint data for cumulative constraints */
132 struct SCIP_ConsData
133 {
134  SCIP_VAR** vars; /**< array of variable representing the start time of each job */
135  SCIP_Bool* downlocks; /**< array to store if the variable has a down lock */
136  SCIP_Bool* uplocks; /**< array to store if the variable has an uplock */
137  SCIP_CONS** linkingconss; /**< array of linking constraints for the integer variables */
138  SCIP_ROW** demandrows; /**< array of rows of linear relaxation of this problem */
139  SCIP_ROW** scoverrows; /**< array of rows of small cover cuts of this problem */
140  SCIP_ROW** bcoverrows; /**< array of rows of big cover cuts of this problem */
141  int* demands; /**< array containing corresponding demands */
142  int* durations; /**< array containing corresponding durations */
143  SCIP_Real resstrength1; /**< stores the resource strength 1*/
144  SCIP_Real resstrength2; /**< stores the resource strength 2 */
145  SCIP_Real cumfactor1; /**< stroes the cumulativeness of the constraint */
146  SCIP_Real disjfactor1; /**< stores the disjunctiveness of the constraint */
147  SCIP_Real disjfactor2; /**< stores the disjunctiveness of the constraint */
148  SCIP_Real estimatedstrength;
149  int nvars; /**< number of variables */
150  int varssize; /**< size of the arrays */
151  int ndemandrows; /**< number of rows of cumulative constrint for linear relaxation */
152  int demandrowssize; /**< size of array rows of demand rows */
153  int nscoverrows; /**< number of rows of small cover cuts */
154  int scoverrowssize; /**< size of array of small cover cuts */
155  int nbcoverrows; /**< number of rows of big cover cuts */
156  int bcoverrowssize; /**< size of array of big cover cuts */
157  int capacity; /**< available cumulative capacity */
158 
159  int hmin; /**< left bound of time axis to be considered (including hmin) */
160  int hmax; /**< right bound of time axis to be considered (not including hmax) */
161 
162  unsigned int signature; /**< constraint signature which is need for pairwise comparison */
163 
164  unsigned int validsignature:1; /**< is the signature valid */
165  unsigned int normalized:1; /**< is the constraint normalized */
166  unsigned int covercuts:1; /**< cover cuts are created? */
167  unsigned int propagated:1; /**< is constraint propagted */
168  unsigned int varbounds:1; /**< bool to store if variable bound strengthening was already preformed */
169  unsigned int triedsolving:1; /**< bool to store if we tried already to solve that constraint as independent subproblem */
170 
171 #ifdef SCIP_STATISTIC
172  int maxpeak;
173 #endif
174 };
175 
176 /** constraint handler data */
177 struct SCIP_ConshdlrData
178 {
179  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
180 
181  SCIP_Bool usebinvars; /**< should the binary variables be used? */
182  SCIP_Bool cutsasconss; /**< should the cumulative constraint create cuts as knapsack constraints? */
183  SCIP_Bool ttinfer; /**< should time-table (core-times) propagator be used to infer bounds? */
184  SCIP_Bool efcheck; /**< should edge-finding be used to detect an overload? */
185  SCIP_Bool efinfer; /**< should edge-finding be used to infer bounds? */
186  SCIP_Bool useadjustedjobs; /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
187  SCIP_Bool ttefcheck; /**< should time-table edge-finding be used to detect an overload? */
188  SCIP_Bool ttefinfer; /**< should time-table edge-finding be used to infer bounds? */
189  SCIP_Bool localcuts; /**< should cuts be added only locally? */
190  SCIP_Bool usecovercuts; /**< should covering cuts be added? */
191  SCIP_Bool sepaold; /**< shall old sepa algo be applied? */
192 
193 
194  SCIP_Bool fillbranchcands; /**< should branching candidates be added to storage? */
195 
196  SCIP_Bool dualpresolve; /**< should dual presolving be applied? */
197  SCIP_Bool coeftightening; /**< should coeffisient tightening be applied? */
198  SCIP_Bool normalize; /**< should demands and capacity be normalized? */
199  SCIP_Bool disjunctive; /**< extract disjunctive constraints? */
200  SCIP_Bool detectdisjunctive; /**< search for conflict set via maximal cliques to detect disjunctive constraints */
201  SCIP_Bool detectvarbounds; /**< search for conflict set via maximal cliques to detect variable bound constraints */
202  SCIP_Bool usebdwidening; /**< should bound widening be used during conflict analysis? */
203  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
204  SCIP_Bool detectedredundant; /**< was detection of redundant constraints already performed? */
205 
206  SCIP_Longint maxnodes; /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
207 
208  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)); /**< method to use a single cumulative condition */
209 
210  /* statistic values which are collected if SCIP_STATISTIC is defined */
211 #ifdef SCIP_STATISTIC
212  SCIP_Longint nlbtimetable; /**< number of times the lower bound was tightened by the time-table propagator */
213  SCIP_Longint nubtimetable; /**< number of times the upper bound was tightened by the time-table propagator */
214  SCIP_Longint ncutofftimetable; /**< number of times the a cutoff was detected due to time-table propagator */
215  SCIP_Longint nlbedgefinder; /**< number of times the lower bound was tightened by the edge-finder propagator */
216  SCIP_Longint nubedgefinder; /**< number of times the upper bound was tightened by the edge-finder propagator */
217  SCIP_Longint ncutoffedgefinder; /**< number of times the a cutoff was detected due to edge-finder propagator */
218  SCIP_Longint ncutoffoverload; /**< number of times the a cutoff was detected due to overload checking via edge-finding */
219  SCIP_Longint nlbTTEF; /**< number of times the lower bound was tightened by time-table edge-finding */
220  SCIP_Longint nubTTEF; /**< number of times the upper bound was tightened by time-table edge-finding */
221  SCIP_Longint ncutoffoverloadTTEF;/**< number of times the a cutoff was detected due to overload checking via time-table edge-finding */
222 
223  int nirrelevantjobs; /**< number of time a irrelevant/redundant jobs was removed form a constraint */
224  int nalwaysruns; /**< number of time a job removed form a constraint which run completely during the effective horizon */
225  int nremovedlocks; /**< number of times a up or down lock was removed */
226  int ndualfixs; /**< number of times a dual fix was performed by a single constraint */
227  int ndecomps; /**< number of times a constraint was decomposed */
228  int ndualbranchs; /**< number of times a dual branch was discoverd and applicable via probing */
229  int nallconsdualfixs; /**< number of times a dual fix was performed due to knowledge of all cumulative constraints */
230  int naddedvarbounds; /**< number of added variable bounds constraints */
231  int naddeddisjunctives; /**< number of added disjunctive constraints */
232 
233  SCIP_Bool iscopy; /**< Boolean to store if constraint handler is part of a copy */
234 #endif
235 };
236 
237 /**@name Inference Information Methods
238  *
239  * An inference information can be passed with each domain reduction to SCIP. This information is passed back to the
240  * constraint handler if the corresponding bound change has to be explained. It can be used to store information which
241  * help to construct a reason/explanation for a bound change. The inference information is limited to size of integer.
242  *
243  * In case of the cumulative constraint handler we store the used propagation algorithms for that particular bound
244  * change and the earliest start and latest completion time of all jobs in the conflict set.
245  *
246  * @{
247  */
248 
249 /** Propagation rules */
250 enum Proprule
251 {
252  PROPRULE_1_CORETIMES = 1, /**< core-time propagator */
253  PROPRULE_2_EDGEFINDING = 2, /**< edge-finder */
254  PROPRULE_3_TTEF = 3 /**< time-table edeg-finding */
255 };
256 typedef enum Proprule PROPRULE;
258 /** inference information */
259 struct InferInfo
260 {
261  union
262  {
263  /** struct to use the inference information */
264  struct
265  {
266  unsigned int proprule:2; /**< propagation rule that was applied */
267  unsigned int data1:15; /**< data field one */
268  unsigned int data2:15; /**< data field two */
269  } asbits;
270  int asint; /**< inference information as a single int value */
271  } val;
272 };
273 typedef struct InferInfo INFERINFO;
275 /** converts an integer into an inference information */
276 static
277 INFERINFO intToInferInfo(
278  int i /**< integer to convert */
279  )
280 {
281  INFERINFO inferinfo;
282 
283  inferinfo.val.asint = i;
284 
285  return inferinfo;
286 }
287 
288 /** converts an inference information into an int */
289 static
290 int inferInfoToInt(
291  INFERINFO inferinfo /**< inference information to convert */
292  )
293 {
294  return inferinfo.val.asint;
295 }
296 
297 /** returns the propagation rule stored in the inference information */
298 static
300  INFERINFO inferinfo /**< inference information to convert */
301  )
302 {
303  return (PROPRULE) inferinfo.val.asbits.proprule;
304 }
305 
306 /** returns data field one of the inference information */
307 static
309  INFERINFO inferinfo /**< inference information to convert */
310  )
311 {
312  return (int) inferinfo.val.asbits.data1;
313 }
314 
315 /** returns data field two of the inference information */
316 static
318  INFERINFO inferinfo /**< inference information to convert */
319  )
320 {
321  return (int) inferinfo.val.asbits.data2;
322 }
323 
324 
325 /** constructs an inference information out of a propagation rule, an earliest start and a latest completion time */
326 static
327 INFERINFO getInferInfo(
328  PROPRULE proprule, /**< propagation rule that deduced the value */
329  int data1, /**< data field one */
330  int data2 /**< data field two */
331  )
332 {
333  INFERINFO inferinfo;
334 
335  /* check that the data menber are in the range of the available bits */
336  assert((int)proprule <= (1<<2)-1); /*lint !e685*/
337  assert(data1 >= 0 && data1 < (1<<15));
338  assert(data2 >= 0 && data2 < (1<<15));
339 
340  inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
341  inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
342  inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
343 
344  return inferinfo;
345 }
346 
347 /**@} */
348 
349 /*
350  * Local methods
351  */
352 
353 /**@name Miscellaneous Methods
354  *
355  * @{
356  */
357 
358 #ifndef NDEBUG
359 
360 /** compute the core of a job which lies in certain interval [begin, end) */
361 static
363  int begin, /**< begin of the interval */
364  int end, /**< end of the interval */
365  int ect, /**< earliest completion time */
366  int lst /**< latest start time */
367  )
368 {
369  int core;
370 
371  core = MAX(0, MIN(end, ect) - MAX(lst, begin));
372 
373  return core;
374 }
375 #else
376 #define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
377 #endif
378 
379 /** returns the implied earliest start time */
380 static
382  SCIP* scip, /**< SCIP data structure */
383  SCIP_VAR* var, /**< variable for which the implied est should be returned */
384  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
385  int* est /**< pointer to store the implied earliest start time */
386  )
387 { /*lint --e{715}*/
388 #if 0
389  SCIP_VAR** vbdvars;
390  SCIP_VAR* vbdvar;
391  SCIP_Real* vbdcoefs;
392  SCIP_Real* vbdconsts;
393  void* image;
394  int nvbdvars;
395  int v;
396 #endif
397 
398  (*est) = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
399 
400 #if 0
401  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
402 
403  nvbdvars = SCIPvarGetNVlbs(var);
404  vbdvars = SCIPvarGetVlbVars(var);
405  vbdcoefs = SCIPvarGetVlbCoefs(var);
406  vbdconsts = SCIPvarGetVlbConstants(var);
407 
408  for( v = 0; v < nvbdvars; ++v )
409  {
410  vbdvar = vbdvars[v];
411  assert(vbdvar != NULL);
412 
413  image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
414 
415  if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
416  {
417  int duration;
418  int vbdconst;
419 
420  duration = (int)(size_t)image;
421  vbdconst = SCIPconvertRealToInt(scip, vbdconsts[v]);
422 
423  SCIPdebugMsg(scip, "check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
425  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
426 
427  if( duration >= vbdconst )
428  {
429  int impliedest;
430 
431  impliedest = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
432 
433  if( (*est) < impliedest )
434  {
435  (*est) = impliedest;
436 
437  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
438  }
439  }
440  }
441  }
442 #endif
443 
444  return SCIP_OKAY;
445 }
446 
447 /** returns the implied latest completion time */
448 static
450  SCIP* scip, /**< SCIP data structure */
451  SCIP_VAR* var, /**< variable for which the implied est should be returned */
452  int duration, /**< duration of the given job */
453  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
454  int* lct /**< pointer to store the implied latest completion time */
455  )
456 { /*lint --e{715}*/
457 #if 0
458  SCIP_VAR** vbdvars;
459  SCIP_VAR* vbdvar;
460  SCIP_Real* vbdcoefs;
461  SCIP_Real* vbdconsts;
462  int nvbdvars;
463  int v;
464 #endif
465 
466  (*lct) = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
467 
468 #if 0
469  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
470 
471  nvbdvars = SCIPvarGetNVubs(var);
472  vbdvars = SCIPvarGetVubVars(var);
473  vbdcoefs = SCIPvarGetVubCoefs(var);
474  vbdconsts = SCIPvarGetVubConstants(var);
475 
476  for( v = 0; v < nvbdvars; ++v )
477  {
478  vbdvar = vbdvars[v];
479  assert(vbdvar != NULL);
480 
481  if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
482  {
483  int vbdconst;
484 
485  vbdconst = SCIPconvertRealToInt(scip, -vbdconsts[v]);
486 
487  SCIPdebugMsg(scip, "check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
489  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
490 
491  if( duration >= -vbdconst )
492  {
493  int impliedlct;
494 
495  impliedlct = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
496 
497  if( (*lct) > impliedlct )
498  {
499  (*lct) = impliedlct;
500 
501  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
502  }
503  }
504  }
505  }
506 #endif
507 
508  return SCIP_OKAY;
509 }
510 
511 /** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
512 static
514  SCIP* scip, /**< SCIP data structure */
515  SCIP_CONSDATA* consdata, /**< constraint data */
516  SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
517  int** coefs, /**< pointer to store the coefficients */
518  int* nvars, /**< number if collect binary variables */
519  int* startindices, /**< permutation with rspect to the start times */
520  int curtime, /**< current point in time */
521  int nstarted, /**< number of jobs that start before the curtime or at curtime */
522  int nfinished /**< number of jobs that finished before curtime or at curtime */
523  )
524 {
525  int nrowvars;
526  int startindex;
527  int size;
528 
529  size = 10;
530  nrowvars = 0;
531  startindex = nstarted - 1;
532 
533  SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
534  SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
535 
536  /* search for the (nstarted - nfinished) jobs which are active at curtime */
537  while( nstarted - nfinished > nrowvars )
538  {
539  SCIP_VAR* var;
540  int endtime;
541  int duration;
542  int demand;
543  int varidx;
544 
545  /* collect job information */
546  varidx = startindices[startindex];
547  assert(varidx >= 0 && varidx < consdata->nvars);
548 
549  var = consdata->vars[varidx];
550  duration = consdata->durations[varidx];
551  demand = consdata->demands[varidx];
552  assert(var != NULL);
553 
554  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
555 
556  /* check the end time of this job is larger than the curtime; in this case the job is still running */
557  if( endtime > curtime )
558  {
559  SCIP_VAR** binvars;
560  int* vals;
561  int nbinvars;
562  int start;
563  int end;
564  int b;
565 
566  /* check if the linking constraints exists */
567  assert(SCIPexistsConsLinking(scip, var));
568  assert(SCIPgetConsLinking(scip, var) != NULL);
569  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
570 
571  /* collect linking constraint information */
572  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
573  vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
574 
575  start = curtime - duration + 1;
576  end = MIN(curtime, endtime - duration);
577 
578  for( b = 0; b < nbinvars; ++b )
579  {
580  if( vals[b] < start )
581  continue;
582 
583  if( vals[b] > end )
584  break;
585 
586  assert(binvars[b] != NULL);
587 
588  /* ensure array proper array size */
589  if( size == *nvars )
590  {
591  size *= 2;
592  SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
593  SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
594  }
595 
596  (*vars)[*nvars] = binvars[b];
597  (*coefs)[*nvars] = demand;
598  (*nvars)++;
599  }
600  nrowvars++;
601  }
602 
603  startindex--;
604  }
605 
606  return SCIP_OKAY;
607 }
608 
609 /** collect all integer variable which belong to jobs which can run at the point of interest */
610 static
612  SCIP* scip, /**< SCIP data structure */
613  SCIP_CONSDATA* consdata, /**< constraint data */
614  SCIP_VAR*** activevars, /**< jobs that are currently running */
615  int* startindices, /**< permutation with rspect to the start times */
616  int curtime, /**< current point in time */
617  int nstarted, /**< number of jobs that start before the curtime or at curtime */
618  int nfinished, /**< number of jobs that finished before curtime or at curtime */
619  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
620  int* lhs /**< lhs for the new row sum of lbs + minoffset */
621  )
622 {
623  SCIP_VAR* var;
624  int startindex;
625  int endtime;
626  int duration;
627  int starttime;
628 
629  int varidx;
630  int sumofstarts;
631  int mindelta;
632  int counter;
633 
634  assert(curtime >= consdata->hmin);
635  assert(curtime < consdata->hmax);
636 
637  counter = 0;
638  sumofstarts = 0;
639 
640  mindelta = INT_MAX;
641 
642  startindex = nstarted - 1;
643 
644  /* search for the (nstarted - nfinished) jobs which are active at curtime */
645  while( nstarted - nfinished > counter )
646  {
647  assert(startindex >= 0);
648 
649  /* collect job information */
650  varidx = startindices[startindex];
651  assert(varidx >= 0 && varidx < consdata->nvars);
652 
653  var = consdata->vars[varidx];
654  duration = consdata->durations[varidx];
655  assert(duration > 0);
656  assert(var != NULL);
657 
658  if( lower )
659  starttime = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
660  else
661  starttime = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
662 
663  endtime = MIN(starttime + duration, consdata->hmax);
664 
665  /* check the end time of this job is larger than the curtime; in this case the job is still running */
666  if( endtime > curtime )
667  {
668  (*activevars)[counter] = var;
669  sumofstarts += starttime;
670  mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
671  counter++;
672  }
673 
674  startindex--;
675  }
676 
677  assert(mindelta > 0);
678  *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
679 
680  return SCIP_OKAY;
681 }
682 
683 /** initialize the sorted event point arrays */
684 static
686  SCIP* scip, /**< SCIP data structure */
687  int nvars, /**< number of start time variables (activities) */
688  SCIP_VAR** vars, /**< array of start time variables */
689  int* durations, /**< array of durations per start time variable */
690  int* starttimes, /**< array to store sorted start events */
691  int* endtimes, /**< array to store sorted end events */
692  int* startindices, /**< permutation with rspect to the start times */
693  int* endindices, /**< permutation with rspect to the end times */
694  SCIP_Bool local /**< shall local bounds be used */
695  )
696 {
697  SCIP_VAR* var;
698  int j;
699 
700  assert(vars != NULL || nvars == 0);
701 
702  /* assign variables, start and endpoints to arrays */
703  for ( j = 0; j < nvars; ++j )
704  {
705  assert(vars != NULL);
706 
707  var = vars[j];
708  assert(var != NULL);
709 
710  if( local )
711  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
712  else
713  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
714 
715  startindices[j] = j;
716 
717  if( local )
718  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
719  else
720  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
721 
722  endindices[j] = j;
723 
724  }
725 
726  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
727  SCIPsortIntInt(starttimes, startindices, j);
728  SCIPsortIntInt(endtimes, endindices, j);
729 }
730 
731 /** initialize the sorted event point arrays w.r.t. the given primal solutions */
732 static
734  SCIP* scip, /**< SCIP data structure */
735  SCIP_SOL* sol, /**< solution */
736  int nvars, /**< number of start time variables (activities) */
737  SCIP_VAR** vars, /**< array of start time variables */
738  int* durations, /**< array of durations per start time variable */
739  int* starttimes, /**< array to store sorted start events */
740  int* endtimes, /**< array to store sorted end events */
741  int* startindices, /**< permutation with rspect to the start times */
742  int* endindices /**< permutation with rspect to the end times */
743  )
744 {
745  SCIP_VAR* var;
746  int j;
747 
748  assert(vars != NULL || nvars == 0);
749 
750  /* assign variables, start and endpoints to arrays */
751  for ( j = 0; j < nvars; ++j )
752  {
753  assert(vars != NULL);
754 
755  var = vars[j];
756  assert(var != NULL);
757 
758  starttimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
759  startindices[j] = j;
760 
761  endtimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
762  endindices[j] = j;
763 
764  }
765 
766  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
767  SCIPsortIntInt(starttimes, startindices, j);
768  SCIPsortIntInt(endtimes, endindices, j);
769 }
770 
771 /** initialize the sorted event point arrays
772  *
773  * @todo Check the separation process!
774  */
775 static
777  SCIP* scip, /**< SCIP data structure */
778  SCIP_CONSDATA* consdata, /**< constraint data */
779  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
780  int* starttimes, /**< array to store sorted start events */
781  int* endtimes, /**< array to store sorted end events */
782  int* startindices, /**< permutation with rspect to the start times */
783  int* endindices, /**< permutation with rspect to the end times */
784  int* nvars, /**< number of variables that are integral */
785  SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
786  )
787 {
788  SCIP_VAR* var;
789  int tmpnvars;
790  int j;
791 
792  tmpnvars = consdata->nvars;
793  *nvars = 0;
794 
795  /* assign variables, start and endpoints to arrays */
796  for ( j = 0; j < tmpnvars; ++j )
797  {
798  var = consdata->vars[j];
799  assert(var != NULL);
800  assert(consdata->durations[j] > 0);
801  assert(consdata->demands[j] > 0);
802 
803  if( lower )
804  {
805  /* only consider jobs that are at their lower or upper bound */
806  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
807  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
808  continue;
809 
810 
811  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
812  startindices[*nvars] = j;
813 
814  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
815  endindices[*nvars] = j;
816 
817  SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
818  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
819  consdata->durations[j],
820  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
821  consdata->demands[startindices[*nvars]]);
822 
823  (*nvars)++;
824  }
825  else
826  {
827  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
828  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
829  continue;
830 
831  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
832  startindices[*nvars] = j;
833 
834  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
835  endindices[*nvars] = j;
836 
837  SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
838  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
839  consdata->durations[j],
840  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
841  consdata->demands[startindices[*nvars]]);
842 
843  (*nvars)++;
844  }
845  }
846 
847  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
848  SCIPsortIntInt(starttimes, startindices, *nvars);
849  SCIPsortIntInt(endtimes, endindices, *nvars);
850 
851 #ifdef SCIP_DEBUG
852  SCIPdebugMsg(scip, "sorted output %d\n", *nvars);
853 
854  for ( j = 0; j < *nvars; ++j )
855  {
856  SCIPdebugMsg(scip, "%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
857  startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
858  consdata->demands[startindices[j]]);
859  }
860 
861  for ( j = 0; j < *nvars; ++j )
862  {
863  SCIPdebugMsg(scip, "%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
864  consdata->demands[endindices[j]]);
865  }
866 #endif
867 }
868 
869 #ifdef SCIP_STATISTIC
870 /** this method checks for relevant intervals for energetic reasoning */
871 static
872 SCIP_RETCODE computeRelevantEnergyIntervals(
873  SCIP* scip, /**< SCIP data structure */
874  int nvars, /**< number of start time variables (activities) */
875  SCIP_VAR** vars, /**< array of start time variables */
876  int* durations, /**< array of durations */
877  int* demands, /**< array of demands */
878  int capacity, /**< cumulative capacity */
879  int hmin, /**< left bound of time axis to be considered (including hmin) */
880  int hmax, /**< right bound of time axis to be considered (not including hmax) */
881  int** timepoints, /**< array to store relevant points in time */
882  SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
883  int* ntimepoints, /**< pointer to store the number of timepoints */
884  int* maxdemand, /**< pointer to store maximum over all demands */
885  SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
886  )
887 {
888  int* starttimes; /* stores when each job is starting */
889  int* endtimes; /* stores when each job ends */
890  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
891  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
892 
893  SCIP_Real totaldemand;
894  int curtime; /* point in time which we are just checking */
895  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
896 
897  int j;
898 
899  assert( scip != NULL );
900  assert(durations != NULL);
901  assert(demands != NULL);
902  assert(capacity >= 0);
903 
904  /* if no activities are associated with this cumulative then this constraint is redundant */
905  if( nvars == 0 )
906  return SCIP_OKAY;
907 
908  assert(vars != NULL);
909 
910  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
911  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
912  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
913  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
914 
915  /* create event point arrays */
916  createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
917 
918  endindex = 0;
919  totaldemand = 0.0;
920 
921  *ntimepoints = 0;
922  (*timepoints)[0] = starttimes[0];
923  (*cumulativedemands)[0] = 0;
924  *maxdemand = 0;
925 
926  /* check each startpoint of a job whether the capacity is kept or not */
927  for( j = 0; j < nvars; ++j )
928  {
929  int lct;
930  int idx;
931 
932  curtime = starttimes[j];
933 
934  if( curtime >= hmax )
935  break;
936 
937  /* free all capacity usages of jobs the are no longer running */
938  while( endindex < nvars && endtimes[endindex] <= curtime )
939  {
940  int est;
941 
942  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
943  {
944  (*ntimepoints)++;
945  (*timepoints)[*ntimepoints] = endtimes[endindex];
946  (*cumulativedemands)[*ntimepoints] = 0;
947  }
948 
949  idx = endindices[endindex];
950  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
951  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
952  endindex++;
953 
954  (*cumulativedemands)[*ntimepoints] = totaldemand;
955  }
956 
957  idx = startindices[j];
958  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
959  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
960 
961  if( (*timepoints)[*ntimepoints] < curtime )
962  {
963  (*ntimepoints)++;
964  (*timepoints)[*ntimepoints] = curtime;
965  (*cumulativedemands)[*ntimepoints] = 0;
966  }
967 
968  (*cumulativedemands)[*ntimepoints] = totaldemand;
969 
970  /* add the relative capacity requirements for all job which start at the curtime */
971  while( j+1 < nvars && starttimes[j+1] == curtime )
972  {
973  ++j;
974  idx = startindices[j];
975  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
976  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
977 
978  (*cumulativedemands)[*ntimepoints] = totaldemand;
979  }
980  } /*lint --e{850}*/
981 
982  /* free all capacity usages of jobs that are no longer running */
983  while( endindex < nvars/* && endtimes[endindex] < hmax*/)
984  {
985  int est;
986  int idx;
987 
988  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
989  {
990  (*ntimepoints)++;
991  (*timepoints)[*ntimepoints] = endtimes[endindex];
992  (*cumulativedemands)[*ntimepoints] = 0;
993  }
994 
995  idx = endindices[endindex];
996  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
997  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
998  (*cumulativedemands)[*ntimepoints] = totaldemand;
999 
1000  ++endindex;
1001  }
1002 
1003  (*ntimepoints)++;
1004  /* compute minimum free capacity */
1005  (*minfreecapacity) = INT_MAX;
1006  for( j = 0; j < *ntimepoints; ++j )
1007  {
1008  if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
1009  *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
1010  }
1011 
1012  /* free buffer arrays */
1013  SCIPfreeBufferArray(scip, &endindices);
1014  SCIPfreeBufferArray(scip, &startindices);
1015  SCIPfreeBufferArray(scip, &endtimes);
1016  SCIPfreeBufferArray(scip, &starttimes);
1017 
1018  return SCIP_OKAY;
1019 }
1020 
1021 /** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1022 static
1023 SCIP_RETCODE evaluateCumulativeness(
1024  SCIP* scip, /**< pointer to scip */
1025  SCIP_CONS* cons /**< cumulative constraint */
1026  )
1027 {
1028  SCIP_CONSDATA* consdata;
1029  int nvars;
1030  int v;
1031  int capacity;
1032 
1033  /* output values: */
1034  SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
1035  SCIP_Real cumfactor1;
1036  SCIP_Real resstrength1; /* overall strength */
1037  SCIP_Real resstrength2; /* timepoint wise maximum */
1038 
1039  /* helpful variables: */
1040  SCIP_Real globalpeak;
1041  SCIP_Real globalmaxdemand;
1042 
1043  /* get constraint data structure */
1044  consdata = SCIPconsGetData(cons);
1045  assert(consdata != NULL);
1046 
1047  nvars = consdata->nvars;
1048  capacity = consdata->capacity;
1049  globalpeak = 0.0;
1050  globalmaxdemand = 0.0;
1051 
1052  disjfactor2 = 0.0;
1053  cumfactor1 = 0.0;
1054  resstrength2 = 0.0;
1055 
1056  /* check each starting time (==each job, but inefficient) */
1057  for( v = 0; v < nvars; ++v )
1058  {
1059  SCIP_Real peak;
1060  SCIP_Real maxdemand;
1061  SCIP_Real deltademand;
1062  int ndemands;
1063  int nlarge;
1064 
1065  int timepoint;
1066  int j;
1067  timepoint = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
1068  peak = consdata->demands[v];
1069  ndemands = 1;
1070  maxdemand = 0;
1071  nlarge = 0;
1072 
1073  if( consdata->demands[v] > capacity / 3 )
1074  nlarge++;
1075 
1076  for( j = 0; j < nvars; ++j )
1077  {
1078  int lb;
1079 
1080  if( j == v )
1081  continue;
1082 
1083  maxdemand = 0.0;
1084  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
1085 
1086  if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
1087  {
1088  peak += consdata->demands[j];
1089  ndemands++;
1090 
1091  if( consdata->demands[j] > consdata->capacity / 3 )
1092  nlarge++;
1093  }
1094  }
1095 
1096  deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
1097  globalpeak = MAX(globalpeak, peak);
1098  globalmaxdemand = MAX(globalmaxdemand, maxdemand);
1099 
1100  if( peak > capacity )
1101  {
1102  disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
1103  cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
1104  resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
1105  }
1106  }
1107 
1108  resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
1109 
1110  consdata->maxpeak = SCIPconvertRealToInt(scip, globalpeak);
1111  consdata->disjfactor2 = disjfactor2;
1112  consdata->cumfactor1 = cumfactor1;
1113  consdata->resstrength2 = resstrength2;
1114  consdata->resstrength1 = resstrength1;
1115 
1116  /* get estimated res strength */
1117  {
1118  int* timepoints;
1119  SCIP_Real* estimateddemands;
1120  int ntimepoints;
1121  int maxdemand;
1122  SCIP_Real minfreecapacity;
1123 
1124  SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
1125  SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
1126 
1127  ntimepoints = 0;
1128  minfreecapacity = INT_MAX;
1129 
1130 
1131  SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
1132  consdata->durations, consdata->demands,
1133  capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1134  &ntimepoints, &maxdemand, &minfreecapacity) );
1135 
1136  /* free buffer arrays */
1137  SCIPfreeBufferArray(scip, &estimateddemands);
1138  SCIPfreeBufferArray(scip, &timepoints);
1139 
1140  consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
1141  }
1142 
1143  SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
1144  SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
1145  consdata->estimatedstrength);
1146 
1147  return SCIP_OKAY;
1148 }
1149 #endif
1150 
1151 /** gets the active variables together with the constant */
1152 static
1154  SCIP* scip, /**< SCIP data structure */
1155  SCIP_VAR** var, /**< pointer to store the active variable */
1156  int* scalar, /**< pointer to store the scalar */
1157  int* constant /**< pointer to store the constant */
1158  )
1159 {
1160  if( !SCIPvarIsActive(*var) )
1161  {
1162  SCIP_Real realscalar;
1163  SCIP_Real realconstant;
1164 
1165  realscalar = 1.0;
1166  realconstant = 0.0;
1167 
1169 
1170  /* transform variable to active variable */
1171  SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
1172  assert(!SCIPisZero(scip, realscalar));
1173  assert(SCIPvarIsActive(*var));
1174 
1175  if( realconstant < 0.0 )
1176  (*constant) = -SCIPconvertRealToInt(scip, -realconstant);
1177  else
1178  (*constant) = SCIPconvertRealToInt(scip, realconstant);
1179 
1180  if( realscalar < 0.0 )
1181  (*scalar) = -SCIPconvertRealToInt(scip, -realscalar);
1182  else
1183  (*scalar) = SCIPconvertRealToInt(scip, realscalar);
1184  }
1185  else
1186  {
1187  (*scalar) = 1;
1188  (*constant) = 0;
1189  }
1190 
1191  assert(*scalar != 0);
1192 
1193  return SCIP_OKAY;
1194 }
1195 
1196 /** computes the total energy of all jobs */
1197 static
1198 int computeTotalEnergy(
1199  int* durations, /**< array of job durations */
1200  int* demands, /**< array of job demands */
1201  int njobs /**< number of jobs */
1202  )
1203 {
1204  int energy;
1205  int j;
1206 
1207  energy = 0;
1208 
1209  for( j = 0; j < njobs; ++j )
1210  energy += durations[j] * demands[j];
1211 
1212  return energy;
1213 }
1214 
1215 /**@} */
1216 
1217 /**@name Default method to solve a cumulative condition
1218  *
1219  * @{
1220  */
1221 
1222 /** solve single cumulative condition using SCIP and a single cumulative constraint */
1223 static
1224 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1226  SCIP* subscip;
1227  SCIP_VAR** subvars;
1228  SCIP_CONS* cons;
1229  SCIP_RETCODE retcode;
1230  char name[SCIP_MAXSTRLEN];
1231  int v;
1232 
1233  assert(njobs > 0);
1234 
1235  (*solved) = FALSE;
1236  (*infeasible) = FALSE;
1237  (*unbounded) = FALSE;
1238  (*error) = FALSE;
1239 
1240  SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1241 
1242  /* initialize the sub-problem */
1243  SCIP_CALL( SCIPcreate(&subscip) );
1244 
1245  /* copy all plugins */
1247 
1248  /* create the subproblem */
1249  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1250 
1251  SCIP_CALL( SCIPallocBlockMemoryArray(subscip, &subvars, njobs) );
1252 
1253  /* create for each job a start time variable */
1254  for( v = 0; v < njobs; ++v )
1255  {
1256  SCIP_Real objval;
1257 
1258  /* construct varibale name */
1259  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
1260 
1261  if( objvals == NULL )
1262  objval = 0.0;
1263  else
1264  objval = objvals[v];
1265 
1266  SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
1267  SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
1268  }
1269 
1270  /* create cumulative constraint */
1271  SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
1272  njobs, subvars, durations, demands, capacity) );
1273 
1274  /* set effective horizon */
1275  SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
1276  SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
1277 
1278  /* add cumulative constraint */
1279  SCIP_CALL( SCIPaddCons(subscip, cons) );
1280  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1281 
1282  /* set CP solver settings
1283  *
1284  * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
1285  * time limit.
1286  */
1288 
1289  /* do not abort subproblem on CTRL-C */
1290  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1291 
1292  /* disable output to console */
1293  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1294 
1295  /* set limits for the subproblem */
1296  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1297  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1298  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1299 
1300  /* forbid recursive call of heuristics and separators solving subMIPs
1301  * todo: really? This method was part of 3.0.1 but not in v31-Bugfix
1302  */
1303  SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
1304 
1305  /* solve single cumulative constraint by branch and bound */
1306  retcode = SCIPsolve(subscip);
1307 
1308  if( retcode != SCIP_OKAY )
1309  (*error) = TRUE;
1310  else
1311  {
1312  SCIPdebugMsg(subscip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1313 
1314  /* evaluated solution status */
1315  switch( SCIPgetStatus(subscip) )
1316  {
1317  case SCIP_STATUS_INFORUNBD:
1319  (*infeasible) = TRUE;
1320  (*solved) = TRUE;
1321  break;
1322  case SCIP_STATUS_UNBOUNDED:
1323  (*unbounded) = TRUE;
1324  (*solved) = TRUE;
1325  break;
1326  case SCIP_STATUS_OPTIMAL:
1327  {
1328  SCIP_SOL* sol;
1329  SCIP_Real solval;
1330 
1331  sol = SCIPgetBestSol(subscip);
1332  assert(sol != NULL);
1333 
1334  for( v = 0; v < njobs; ++v )
1335  {
1336  solval = SCIPgetSolVal(subscip, sol, subvars[v]);
1337 
1338  ests[v] = solval;
1339  lsts[v] = solval;
1340  }
1341  (*solved) = TRUE;
1342  break;
1343  }
1344  case SCIP_STATUS_NODELIMIT:
1346  case SCIP_STATUS_TIMELIMIT:
1347  case SCIP_STATUS_MEMLIMIT:
1349  /* transfer the global bound changes */
1350  for( v = 0; v < njobs; ++v )
1351  {
1352  ests[v] = SCIPvarGetLbGlobal(subvars[v]);
1353  lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
1354  }
1355  (*solved) = FALSE;
1356  break;
1357 
1358  case SCIP_STATUS_UNKNOWN:
1360  case SCIP_STATUS_GAPLIMIT:
1361  case SCIP_STATUS_SOLLIMIT:
1364  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1365  return SCIP_INVALIDDATA;
1366  }
1367  }
1368 
1369  /* release all variables */
1370  for( v = 0; v < njobs; ++v )
1371  {
1372  SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1373  }
1374 
1375  SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
1376 
1377  SCIP_CALL( SCIPfree(&subscip) );
1378 
1379  return SCIP_OKAY;
1380 }
1381 
1382 #if 0
1383 /** solve single cumulative condition using SCIP and the time indexed formulation */
1384 static
1385 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1386 {
1387  SCIP* subscip;
1388  SCIP_VAR*** binvars;
1389  SCIP_RETCODE retcode;
1390  char name[SCIP_MAXSTRLEN];
1391  int minest;
1392  int maxlct;
1393  int t;
1394  int v;
1395 
1396  assert(njobs > 0);
1397 
1398  (*solved) = FALSE;
1399  (*infeasible) = FALSE;
1400  (*unbounded) = FALSE;
1401  (*error) = FALSE;
1402 
1403  SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
1404 
1405  /* initialize the sub-problem */
1406  SCIP_CALL( SCIPcreate(&subscip) );
1407 
1408  /* copy all plugins */
1410 
1411  /* create the subproblem */
1412  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1413 
1414  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
1415 
1416  minest = INT_MAX;
1417  maxlct = INT_MIN;
1418 
1419  /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1420  * partitioning constrain which forces that job starts
1421  */
1422  for( v = 0; v < njobs; ++v )
1423  {
1424  SCIP_CONS* cons;
1425  SCIP_Real objval;
1426  int timeinterval;
1427  int est;
1428  int lst;
1429 
1430  if( objvals == NULL )
1431  objval = 0.0;
1432  else
1433  objval = objvals[v];
1434 
1435  est = ests[v];
1436  lst = lsts[v];
1437 
1438  /* compute number of possible start points */
1439  timeinterval = lst - est + 1;
1440  assert(timeinterval > 0);
1441 
1442  /* compute the smallest earliest start time and largest latest completion time */
1443  minest = MIN(minest, est);
1444  maxlct = MAX(maxlct, lst + durations[v]);
1445 
1446  /* construct constraint name */
1447  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1448 
1449  SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1450 
1451  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
1452 
1453  for( t = 0; t < timeinterval; ++t )
1454  {
1455  SCIP_VAR* binvar;
1456 
1457  /* construct varibale name */
1458  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1459 
1460  SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1461  SCIP_CALL( SCIPaddVar(subscip, binvar) );
1462 
1463  /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1464  SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1465 
1466  binvars[v][t] = binvar;
1467  }
1468 
1469  /* add and release the set partitioning constraint */
1470  SCIP_CALL( SCIPaddCons(subscip, cons) );
1471  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1472  }
1473 
1474  /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1475  hmin = MAX(hmin, minest);
1476  hmax = MIN(hmax, maxlct);
1477  assert(hmin > INT_MIN);
1478  assert(hmax < INT_MAX);
1479  assert(hmin < hmax);
1480 
1481  /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1482  for( t = hmin; t < hmax; ++t )
1483  {
1484  SCIP_CONS* cons;
1485 
1486  /* construct constraint name */
1487  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1488 
1489  /* create an empty knapsack constraint */
1490  SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1491 
1492  /* add all jobs which potentially can be processed at that time point */
1493  for( v = 0; v < njobs; ++v )
1494  {
1495  int duration;
1496  int demand;
1497  int start;
1498  int end;
1499  int est;
1500  int lst;
1501  int k;
1502 
1503  est = ests[v];
1504  lst = lsts[v] ;
1505 
1506  duration = durations[v];
1507  assert(duration > 0);
1508 
1509  /* check if the varibale is processed potentially at time point t */
1510  if( t < est || t >= lst + duration )
1511  continue;
1512 
1513  demand = demands[v];
1514  assert(demand >= 0);
1515 
1516  start = MAX(t - duration + 1, est);
1517  end = MIN(t, lst);
1518 
1519  assert(start <= end);
1520 
1521  for( k = start; k <= end; ++k )
1522  {
1523  assert(binvars[v][k] != NULL);
1524  SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1525  }
1526  }
1527 
1528  /* add and release the knapsack constraint */
1529  SCIP_CALL( SCIPaddCons(subscip, cons) );
1530  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1531  }
1532 
1533  /* do not abort subproblem on CTRL-C */
1534  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1535 
1536  /* disable output to console */
1537  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1538 
1539  /* set limits for the subproblem */
1540  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1541  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1542  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1543 
1544  /* solve single cumulative constraint by branch and bound */
1545  retcode = SCIPsolve(subscip);
1546 
1547  if( retcode != SCIP_OKAY )
1548  (*error) = TRUE;
1549  else
1550  {
1551  SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1552 
1553  /* evaluated solution status */
1554  switch( SCIPgetStatus(subscip) )
1555  {
1556  case SCIP_STATUS_INFORUNBD:
1558  (*infeasible) = TRUE;
1559  (*solved) = TRUE;
1560  break;
1561  case SCIP_STATUS_UNBOUNDED:
1562  (*unbounded) = TRUE;
1563  (*solved) = TRUE;
1564  break;
1565  case SCIP_STATUS_OPTIMAL:
1566  {
1567  SCIP_SOL* sol;
1568 
1569  sol = SCIPgetBestSol(subscip);
1570  assert(sol != NULL);
1571 
1572  for( v = 0; v < njobs; ++v )
1573  {
1574  int timeinterval;
1575  int est;
1576  int lst;
1577 
1578  est = ests[v];
1579  lst = lsts[v];
1580 
1581  /* compute number of possible start points */
1582  timeinterval = lst - est + 1;
1583 
1584  /* check which binary varibale is set to one */
1585  for( t = 0; t < timeinterval; ++t )
1586  {
1587  if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1588  {
1589  ests[v] = est + t;
1590  lsts[v] = est + t;
1591  break;
1592  }
1593  }
1594  }
1595 
1596  (*solved) = TRUE;
1597  break;
1598  }
1599  case SCIP_STATUS_NODELIMIT:
1601  case SCIP_STATUS_TIMELIMIT:
1602  case SCIP_STATUS_MEMLIMIT:
1604  /* transfer the global bound changes */
1605  for( v = 0; v < njobs; ++v )
1606  {
1607  int timeinterval;
1608  int est;
1609  int lst;
1610 
1611  est = ests[v];
1612  lst = lsts[v];
1613 
1614  /* compute number of possible start points */
1615  timeinterval = lst - est + 1;
1616 
1617  /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1618  for( t = 0; t < timeinterval; ++t )
1619  {
1620  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1621  {
1622  ests[v] = est + t;
1623  break;
1624  }
1625  }
1626 
1627  /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1628  for( t = timeinterval - 1; t >= 0; --t )
1629  {
1630  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1631  {
1632  lsts[v] = est + t;
1633  break;
1634  }
1635  }
1636  }
1637  (*solved) = FALSE;
1638  break;
1639 
1640  case SCIP_STATUS_UNKNOWN:
1642  case SCIP_STATUS_GAPLIMIT:
1643  case SCIP_STATUS_SOLLIMIT:
1645  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1646  return SCIP_INVALIDDATA;
1647  }
1648  }
1649 
1650  /* release all variables */
1651  for( v = 0; v < njobs; ++v )
1652  {
1653  int timeinterval;
1654  int est;
1655  int lst;
1656 
1657  est = ests[v];
1658  lst = lsts[v];
1659 
1660  /* compute number of possible start points */
1661  timeinterval = lst - est + 1;
1662 
1663  for( t = 0; t < timeinterval; ++t )
1664  {
1665  SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1666  }
1667  SCIPfreeBufferArray(subscip, &binvars[v]);
1668  }
1669 
1670  SCIPfreeBufferArray(subscip, &binvars);
1671 
1672  SCIP_CALL( SCIPfree(&subscip) );
1673 
1674  return SCIP_OKAY;
1675 }
1676 #endif
1677 
1678 /**@} */
1679 
1680 /**@name Constraint handler data
1681  *
1682  * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1683  * handler.
1684  *
1685  * @{
1686  */
1687 
1688 /** creates constaint handler data for cumulative constraint handler */
1689 static
1691  SCIP* scip, /**< SCIP data structure */
1692  SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1693  SCIP_EVENTHDLR* eventhdlr /**< event handler */
1694  )
1695 {
1696  /* create precedence constraint handler data */
1697  assert(scip != NULL);
1698  assert(conshdlrdata != NULL);
1699  assert(eventhdlr != NULL);
1700 
1701  SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
1702 
1703  /* set event handler for checking if bounds of start time variables are tighten */
1704  (*conshdlrdata)->eventhdlr = eventhdlr;
1705 
1706  /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1707  (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1708 
1709 #ifdef SCIP_STATISTIC
1710  (*conshdlrdata)->nlbtimetable = 0;
1711  (*conshdlrdata)->nubtimetable = 0;
1712  (*conshdlrdata)->ncutofftimetable = 0;
1713  (*conshdlrdata)->nlbedgefinder = 0;
1714  (*conshdlrdata)->nubedgefinder = 0;
1715  (*conshdlrdata)->ncutoffedgefinder = 0;
1716  (*conshdlrdata)->ncutoffoverload = 0;
1717  (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1718 
1719  (*conshdlrdata)->nirrelevantjobs = 0;
1720  (*conshdlrdata)->nalwaysruns = 0;
1721  (*conshdlrdata)->nremovedlocks = 0;
1722  (*conshdlrdata)->ndualfixs = 0;
1723  (*conshdlrdata)->ndecomps = 0;
1724  (*conshdlrdata)->ndualbranchs = 0;
1725  (*conshdlrdata)->nallconsdualfixs = 0;
1726  (*conshdlrdata)->naddedvarbounds = 0;
1727  (*conshdlrdata)->naddeddisjunctives = 0;
1728 #endif
1729 
1730  return SCIP_OKAY;
1731 }
1732 
1733 /** frees constraint handler data for logic or constraint handler */
1734 static
1735 void conshdlrdataFree(
1736  SCIP* scip, /**< SCIP data structure */
1737  SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1738  )
1739 {
1740  assert(conshdlrdata != NULL);
1741  assert(*conshdlrdata != NULL);
1742 
1743  SCIPfreeBlockMemory(scip, conshdlrdata);
1744 }
1745 
1746 /**@} */
1747 
1748 
1749 /**@name Constraint data methods
1750  *
1751  * @{
1752  */
1753 
1754 /** catches bound change events for all variables in transformed cumulative constraint */
1755 static
1757  SCIP* scip, /**< SCIP data structure */
1758  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1759  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1760  )
1761 {
1762  int v;
1763 
1764  assert(scip != NULL);
1765  assert(consdata != NULL);
1766  assert(eventhdlr != NULL);
1767 
1768  /* catch event for every single variable */
1769  for( v = 0; v < consdata->nvars; ++v )
1770  {
1771  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1772  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1773  }
1774 
1775  return SCIP_OKAY;
1776 }
1777 
1778 /** drops events for variable at given position */
1779 static
1781  SCIP* scip, /**< SCIP data structure */
1782  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1783  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1784  int pos /**< array position of variable to catch bound change events for */
1785  )
1786 {
1787  assert(scip != NULL);
1788  assert(consdata != NULL);
1789  assert(eventhdlr != NULL);
1790  assert(0 <= pos && pos < consdata->nvars);
1791  assert(consdata->vars[pos] != NULL);
1792 
1793  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1794  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1795 
1796  return SCIP_OKAY;
1797 }
1798 
1799 /** drops bound change events for all variables in transformed linear constraint */
1800 static
1802  SCIP* scip, /**< SCIP data structure */
1803  SCIP_CONSDATA* consdata, /**< linear constraint data */
1804  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1805  )
1806 {
1807  int v;
1808 
1809  assert(scip != NULL);
1810  assert(consdata != NULL);
1811 
1812  /* drop event of every single variable */
1813  for( v = 0; v < consdata->nvars; ++v )
1814  {
1815  SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1816  }
1817 
1818  return SCIP_OKAY;
1819 }
1820 
1821 /** initialize variable lock data structure */
1822 static
1823 void initializeLocks(
1824  SCIP_CONSDATA* consdata, /**< constraint data */
1825  SCIP_Bool locked /**< should the variable be locked? */
1826  )
1827 {
1828  int nvars;
1829  int v;
1830 
1831  nvars = consdata->nvars;
1832 
1833  /* initialize locking arrays */
1834  for( v = 0; v < nvars; ++v )
1835  {
1836  consdata->downlocks[v] = locked;
1837  consdata->uplocks[v] = locked;
1838  }
1839 }
1840 
1841 /** creates constraint data of cumulative constraint */
1842 static
1844  SCIP* scip, /**< SCIP data structure */
1845  SCIP_CONSDATA** consdata, /**< pointer to consdata */
1846  SCIP_VAR** vars, /**< array of integer variables */
1847  SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1848  int* durations, /**< array containing corresponding durations */
1849  int* demands, /**< array containing corresponding demands */
1850  int nvars, /**< number of variables */
1851  int capacity, /**< available cumulative capacity */
1852  int hmin, /**< left bound of time axis to be considered (including hmin) */
1853  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1854  SCIP_Bool check /**< is the corresponding constraint a check constraint */
1855  )
1856 {
1857  int v;
1858 
1859  assert(scip != NULL);
1860  assert(consdata != NULL);
1861  assert(vars != NULL || nvars > 0);
1862  assert(demands != NULL);
1863  assert(durations != NULL);
1864  assert(capacity >= 0);
1865  assert(hmin >= 0);
1866  assert(hmin < hmax);
1867 
1868  /* create constraint data */
1869  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1870 
1871  (*consdata)->hmin = hmin;
1872  (*consdata)->hmax = hmax;
1873 
1874  (*consdata)->capacity = capacity;
1875  (*consdata)->demandrows = NULL;
1876  (*consdata)->demandrowssize = 0;
1877  (*consdata)->ndemandrows = 0;
1878  (*consdata)->scoverrows = NULL;
1879  (*consdata)->nscoverrows = 0;
1880  (*consdata)->scoverrowssize = 0;
1881  (*consdata)->bcoverrows = NULL;
1882  (*consdata)->nbcoverrows = 0;
1883  (*consdata)->bcoverrowssize = 0;
1884  (*consdata)->nvars = nvars;
1885  (*consdata)->varssize = nvars;
1886  (*consdata)->signature = 0;
1887  (*consdata)->validsignature = FALSE;
1888  (*consdata)->normalized = FALSE;
1889  (*consdata)->covercuts = FALSE;
1890  (*consdata)->propagated = FALSE;
1891  (*consdata)->varbounds = FALSE;
1892  (*consdata)->triedsolving = FALSE;
1893 
1894  if( nvars > 0 )
1895  {
1896  assert(vars != NULL); /* for flexelint */
1897 
1898  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1899  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1900  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1901  (*consdata)->linkingconss = NULL;
1902 
1903  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1904  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1905 
1906  /* initialize variable lock data structure; the locks are only used if the contraint is a check constraint */
1907  initializeLocks(*consdata, check);
1908 
1909  if( linkingconss != NULL )
1910  {
1911  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
1912  }
1913 
1914  /* transform variables, if they are not yet transformed */
1915  if( SCIPisTransformed(scip) )
1916  {
1917  SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
1918 
1919  /* get transformed variables and do NOT captures these */
1920  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1921 
1922  /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
1923  * been multi-aggregated
1924  */
1925  for( v = 0; v < nvars; ++v )
1926  {
1927  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
1928  }
1929 
1930  if( linkingconss != NULL )
1931  {
1932  /* get transformed constraints and captures these */
1933  SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
1934 
1935  for( v = 0; v < nvars; ++v )
1936  assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
1937  }
1938  }
1939  }
1940  else
1941  {
1942  (*consdata)->vars = NULL;
1943  (*consdata)->downlocks = NULL;
1944  (*consdata)->uplocks = NULL;
1945  (*consdata)->demands = NULL;
1946  (*consdata)->durations = NULL;
1947  (*consdata)->linkingconss = NULL;
1948  }
1949 
1950  /* initialize values for running propagation algorithms efficiently */
1951  (*consdata)->resstrength1 = -1.0;
1952  (*consdata)->resstrength2 = -1.0;
1953  (*consdata)->cumfactor1 = -1.0;
1954  (*consdata)->disjfactor1 = -1.0;
1955  (*consdata)->disjfactor2 = -1.0;
1956  (*consdata)->estimatedstrength = -1.0;
1957 
1958  SCIPstatistic( (*consdata)->maxpeak = -1 );
1959 
1960  return SCIP_OKAY;
1961 }
1962 
1963 /** releases LP rows of constraint data and frees rows array */
1964 static
1966  SCIP* scip, /**< SCIP data structure */
1967  SCIP_CONSDATA** consdata /**< constraint data */
1968  )
1969 {
1970  int r;
1971 
1972  assert(consdata != NULL);
1973  assert(*consdata != NULL);
1974 
1975  for( r = 0; r < (*consdata)->ndemandrows; ++r )
1976  {
1977  assert((*consdata)->demandrows[r] != NULL);
1978  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
1979  }
1980 
1981  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
1982 
1983  (*consdata)->ndemandrows = 0;
1984  (*consdata)->demandrowssize = 0;
1985 
1986  /* free rows of cover cuts */
1987  for( r = 0; r < (*consdata)->nscoverrows; ++r )
1988  {
1989  assert((*consdata)->scoverrows[r] != NULL);
1990  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
1991  }
1992 
1993  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
1994 
1995  (*consdata)->nscoverrows = 0;
1996  (*consdata)->scoverrowssize = 0;
1997 
1998  for( r = 0; r < (*consdata)->nbcoverrows; ++r )
1999  {
2000  assert((*consdata)->bcoverrows[r] != NULL);
2001  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2002  }
2003 
2004  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2005 
2006  (*consdata)->nbcoverrows = 0;
2007  (*consdata)->bcoverrowssize = 0;
2008 
2009  (*consdata)->covercuts = FALSE;
2010 
2011  return SCIP_OKAY;
2012 }
2013 
2014 /** frees a cumulative constraint data */
2015 static
2017  SCIP* scip, /**< SCIP data structure */
2018  SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2019  )
2020 {
2021  int varssize;
2022  int nvars;
2023 
2024  assert(consdata != NULL);
2025  assert(*consdata != NULL);
2026 
2027  nvars = (*consdata)->nvars;
2028  varssize = (*consdata)->varssize;
2029 
2030  if( varssize > 0 )
2031  {
2032  int v;
2033 
2034  /* release and free the rows */
2035  SCIP_CALL( consdataFreeRows(scip, consdata) );
2036 
2037  /* release the linking constraints if they were generated */
2038  if( (*consdata)->linkingconss != NULL )
2039  {
2040  for( v = nvars-1; v >= 0; --v )
2041  {
2042  assert((*consdata)->linkingconss[v] != NULL );
2043  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2044  }
2045 
2046  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2047  }
2048 
2049  /* free arrays */
2050  SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2051  SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2052  SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2053  SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2054  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2055  }
2056 
2057  /* free memory */
2058  SCIPfreeBlockMemory(scip, consdata);
2059 
2060  return SCIP_OKAY;
2061 }
2062 
2063 /** prints cumulative constraint to file stream */
2064 static
2065 void consdataPrint(
2066  SCIP* scip, /**< SCIP data structure */
2067  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2068  FILE* file /**< output file (or NULL for standard output) */
2069  )
2070 {
2071  int v;
2072 
2073  assert(consdata != NULL);
2074 
2075  /* print coefficients */
2076  SCIPinfoMessage( scip, file, "cumulative(");
2077 
2078  for( v = 0; v < consdata->nvars; ++v )
2079  {
2080  assert(consdata->vars[v] != NULL);
2081  if( v > 0 )
2082  SCIPinfoMessage(scip, file, ", ");
2083  SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2084  SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2085  consdata->durations[v], consdata->demands[v]);
2086  }
2087  SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2088 }
2089 
2090 /** deletes coefficient at given position from constraint data */
2091 static
2093  SCIP* scip, /**< SCIP data structure */
2094  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2095  SCIP_CONS* cons, /**< knapsack constraint */
2096  int pos /**< position of coefficient to delete */
2097  )
2098 {
2099  SCIP_CONSHDLR* conshdlr;
2100  SCIP_CONSHDLRDATA* conshdlrdata;
2101 
2102  assert(scip != NULL);
2103  assert(consdata != NULL);
2104  assert(cons != NULL);
2105  assert(SCIPconsIsTransformed(cons));
2106  assert(!SCIPinProbing(scip));
2107 
2108  SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2109  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2110 
2111  /* remove the rounding locks for the deleted variable */
2112  SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2113 
2114  consdata->downlocks[pos] = FALSE;
2115  consdata->uplocks[pos] = FALSE;
2116 
2117  if( consdata->linkingconss != NULL )
2118  {
2119  SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2120  }
2121 
2122  /* get event handler */
2123  conshdlr = SCIPconsGetHdlr(cons);
2124  assert(conshdlr != NULL);
2125  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2126  assert(conshdlrdata != NULL);
2127  assert(conshdlrdata->eventhdlr != NULL);
2128 
2129  /* drop events */
2130  SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2131 
2132  SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2133  SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2134 
2135 
2136  /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2137  * position
2138  */
2139  if( pos != consdata->nvars - 1 )
2140  {
2141  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2142  consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2143  consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2144  consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2145  consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2146 
2147  if( consdata->linkingconss != NULL )
2148  {
2149  consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2150  }
2151  }
2152 
2153  consdata->nvars--;
2154  consdata->validsignature = FALSE;
2155  consdata->normalized = FALSE;
2156 
2157  return SCIP_OKAY;
2158 }
2159 
2160 /** collect linking constraints for each integer variable */
2161 static
2163  SCIP* scip, /**< SCIP data structure */
2164  SCIP_CONSDATA* consdata /**< pointer to consdata */
2165  )
2166 {
2167  int nvars;
2168  int v;
2169 
2170  assert(scip != NULL);
2171  assert(consdata != NULL);
2172 
2173  nvars = consdata->nvars;
2174  assert(nvars > 0);
2175  assert(consdata->linkingconss == NULL);
2176 
2177  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2178 
2179  for( v = 0; v < nvars; ++v )
2180  {
2181  SCIP_CONS* cons;
2182  SCIP_VAR* var;
2183 
2184  var = consdata->vars[v];
2185  assert(var != NULL);
2186 
2187  SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2188 
2189  /* create linking constraint if it does not exist yet */
2190  if( !SCIPexistsConsLinking(scip, var) )
2191  {
2192  char name[SCIP_MAXSTRLEN];
2193 
2194  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2195 
2196  /* creates and captures an linking constraint */
2197  SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2198  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2199  SCIP_CALL( SCIPaddCons(scip, cons) );
2200  consdata->linkingconss[v] = cons;
2201  }
2202  else
2203  {
2204  consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2205  SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2206  }
2207 
2208  assert(SCIPexistsConsLinking(scip, var));
2209  assert(consdata->linkingconss[v] != NULL);
2210  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2211  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2212  }
2213 
2214  return SCIP_OKAY;
2215 }
2216 
2217 /**@} */
2218 
2219 
2220 /**@name Check methods
2221  *
2222  * @{
2223  */
2224 
2225 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2226  * given solution is satisfied
2227  */
2228 static
2230  SCIP* scip, /**< SCIP data structure */
2231  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2232  int nvars, /**< number of variables (jobs) */
2233  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2234  int* durations, /**< array containing corresponding durations */
2235  int* demands, /**< array containing corresponding demands */
2236  int capacity, /**< available cumulative capacity */
2237  int hmin, /**< left bound of time axis to be considered (including hmin) */
2238  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2239  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2240  SCIP_CONS* cons, /**< constraint which is checked */
2241  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2242  )
2243 {
2244  int* startsolvalues; /* stores when each job is starting */
2245  int* endsolvalues; /* stores when each job ends */
2246  int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2247  int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2248 
2249  int freecapacity;
2250  int curtime; /* point in time which we are just checking */
2251  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2252  int j;
2253 
2254  assert(scip != NULL);
2255  assert(violated != NULL);
2256 
2257  (*violated) = FALSE;
2258 
2259  if( nvars == 0 )
2260  return SCIP_OKAY;
2261 
2262  assert(vars != NULL);
2263  assert(demands != NULL);
2264  assert(durations != NULL);
2265 
2266  /* compute time points where we have to check whether capacity constraint is infeasible or not */
2267  SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2268  SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2269  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2270  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2271 
2272  /* assign variables, start and endpoints to arrays */
2273  for ( j = 0; j < nvars; ++j )
2274  {
2275  int solvalue;
2276 
2277  /* the constraint of the cumulative constraint handler should be called after the integrality check */
2278  assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2279 
2280  solvalue = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2281 
2282  /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2283  * jobs which start before hmin to hmin
2284  */
2285  startsolvalues[j] = MAX(solvalue, hmin);
2286  startindices[j] = j;
2287 
2288  endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2289  endindices[j] = j;
2290  }
2291 
2292  /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2293  * corresponding indices in the same way)
2294  */
2295  SCIPsortIntInt(startsolvalues, startindices, nvars);
2296  SCIPsortIntInt(endsolvalues, endindices, nvars);
2297 
2298  endindex = 0;
2299  freecapacity = capacity;
2300 
2301  /* check each start point of a job whether the capacity is kept or not */
2302  for( j = 0; j < nvars; ++j )
2303  {
2304  /* only check intervals [hmin,hmax) */
2305  curtime = startsolvalues[j];
2306 
2307  if( curtime >= hmax )
2308  break;
2309 
2310  /* subtract all capacity needed up to this point */
2311  freecapacity -= demands[startindices[j]];
2312  while( j+1 < nvars && startsolvalues[j+1] == curtime )
2313  {
2314  j++;
2315  freecapacity -= demands[startindices[j]];
2316  }
2317 
2318  /* free all capacity usages of jobs that are no longer running */
2319  while( endindex < nvars && curtime >= endsolvalues[endindex] )
2320  {
2321  freecapacity += demands[endindices[endindex]];
2322  ++endindex;
2323  }
2324  assert(freecapacity <= capacity);
2325 
2326  /* check freecapacity to be smaller than zero */
2327  if( freecapacity < 0 && curtime >= hmin )
2328  {
2329  SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2330  (*violated) = TRUE;
2331 
2332  if( printreason )
2333  {
2334  int i;
2335 
2336  /* first state the violated constraints */
2337  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2338 
2339  /* second state the reason */
2340  SCIPinfoMessage(scip, NULL,
2341  ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2342  curtime, capacity, capacity - freecapacity);
2343 
2344  for( i = 0; i <= j; ++i )
2345  {
2346  if( startsolvalues[i] + durations[startindices[i]] > curtime )
2347  {
2348  SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2349  SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2350  demands[startindices[i]]);
2351  }
2352  }
2353  }
2354  break;
2355  }
2356  } /*lint --e{850}*/
2357 
2358  /* free all buffer arrays */
2359  SCIPfreeBufferArray(scip, &endindices);
2360  SCIPfreeBufferArray(scip, &startindices);
2361  SCIPfreeBufferArray(scip, &endsolvalues);
2362  SCIPfreeBufferArray(scip, &startsolvalues);
2363 
2364  return SCIP_OKAY;
2365 }
2366 
2367 /** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2368  * least zero or not. If not (*violated) is set to TRUE
2369  */
2370 static
2372  SCIP* scip, /**< SCIP data structure */
2373  SCIP_CONS* cons, /**< constraint to be checked */
2374  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2375  SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2376  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2377  )
2378 {
2379  SCIP_CONSDATA* consdata;
2380 
2381  assert(scip != NULL);
2382  assert(cons != NULL);
2383  assert(violated != NULL);
2384 
2385  SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2386 
2387  consdata = SCIPconsGetData(cons);
2388  assert(consdata != NULL);
2389 
2390  /* check the cumulative condition */
2391  SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2392  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2393  violated, cons, printreason) );
2394 
2395  return SCIP_OKAY;
2396 }
2397 
2398 /**@} */
2399 
2400 /**@name Conflict analysis
2401  *
2402  * @{
2403  */
2404 
2405 /** resolves the propagation of the core time algorithm */
2406 static
2408  SCIP* scip, /**< SCIP data structure */
2409  int nvars, /**< number of start time variables (activities) */
2410  SCIP_VAR** vars, /**< array of start time variables */
2411  int* durations, /**< array of durations */
2412  int* demands, /**< array of demands */
2413  int capacity, /**< cumulative capacity */
2414  int hmin, /**< left bound of time axis to be considered (including hmin) */
2415  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2416  SCIP_VAR* infervar, /**< inference variable */
2417  int inferdemand, /**< demand of the inference variable */
2418  int inferpeak, /**< time point which causes the propagation */
2419  int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2420  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2421  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2422  int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2423  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2424  )
2425 {
2426  SCIP_VAR* var;
2427  SCIP_Bool* reported;
2428  int duration;
2429  int maxlst;
2430  int minect;
2431  int ect;
2432  int lst;
2433  int j;
2434 
2435  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
2436 
2437  SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2438  SCIPvarGetName(infervar), inferdemand, inferpeak);
2439  assert(nvars > 0);
2440 
2441  /* adjusted capacity */
2442  capacity -= inferdemand;
2443  maxlst = INT_MIN;
2444  minect = INT_MAX;
2445 
2446  SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2447  BMSclearMemoryArray(reported, nvars);
2448 
2449  /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2450  * inference peak and those where the current conflict bounds provide a core at the inference peak
2451  */
2452  for( j = 0; j < nvars && capacity >= 0; ++j )
2453  {
2454  var = vars[j];
2455  assert(var != NULL);
2456 
2457  /* skip inference variable */
2458  if( var == infervar )
2459  continue;
2460 
2461  duration = durations[j];
2462  assert(duration > 0);
2463 
2464  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2465  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2466  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2467  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2468  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2469 
2470  SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2472  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2473 
2474  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2475  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2476 
2477  /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2478  * that job without adding it the explanation
2479  */
2480  if( inferpeak < ect && lst <= inferpeak )
2481  {
2482  capacity -= demands[j];
2483  reported[j] = TRUE;
2484 
2485  maxlst = MAX(maxlst, lst);
2486  minect = MIN(minect, ect);
2487  assert(maxlst < minect);
2488 
2489  if( explanation != NULL )
2490  explanation[j] = TRUE;
2491 
2492  continue;
2493  }
2494 
2495  /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2496  * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2497  * not part of the conflict yet we get the global bounds back.
2498  */
2499  ect = SCIPconvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2500  lst = SCIPconvertRealToInt(scip, SCIPgetConflictVarUb(scip, var));
2501 
2502  /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2503  * of that job without and collect the job as part of the explanation
2504  *
2505  * @note we do not need to reported that job to SCIP since the required bounds are already reported
2506  */
2507  if( inferpeak < ect && lst <= inferpeak )
2508  {
2509  capacity -= demands[j];
2510  reported[j] = TRUE;
2511 
2512  maxlst = MAX(maxlst, lst);
2513  minect = MIN(minect, ect);
2514  assert(maxlst < minect);
2515 
2516  if( explanation != NULL )
2517  explanation[j] = TRUE;
2518  }
2519  }
2520 
2521  if( capacity >= 0 )
2522  {
2523  int* cands;
2524  int* canddemands;
2525  int ncands;
2526  int c;
2527 
2528  SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2529  SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2530  ncands = 0;
2531 
2532  /* collect all cores of the variables which lay in the considered time window except the inference variable */
2533  for( j = 0; j < nvars; ++j )
2534  {
2535  var = vars[j];
2536  assert(var != NULL);
2537 
2538  /* skip inference variable */
2539  if( var == infervar || reported[j] )
2540  continue;
2541 
2542  duration = durations[j];
2543  assert(duration > 0);
2544 
2545  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2546  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2547  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2548  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2549  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2550 
2551  /* collect local core information */
2552  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2553  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2554 
2555  SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2556  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2557  SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2558 
2559  /* check if the inference peak is part of the core */
2560  if( inferpeak < ect && lst <= inferpeak )
2561  {
2562  cands[ncands] = j;
2563  canddemands[ncands] = demands[j];
2564  ncands++;
2565 
2566  capacity -= demands[j];
2567  }
2568  }
2569 
2570  /* sort candidates indices w.r.t. their demands */
2571  SCIPsortDownIntInt(canddemands, cands, ncands);
2572 
2573  assert(capacity < 0);
2574  assert(ncands > 0);
2575 
2576  /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2577  while( capacity + canddemands[ncands-1] < 0 )
2578  {
2579  ncands--;
2580  capacity += canddemands[ncands];
2581  assert(ncands > 0);
2582  }
2583 
2584  /* compute the size (number of time steps) of the job cores */
2585  for( c = 0; c < ncands; ++c )
2586  {
2587  var = vars[cands[c]];
2588  assert(var != NULL);
2589 
2590  duration = durations[cands[c]];
2591 
2592  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2593  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2594 
2595  maxlst = MAX(maxlst, lst);
2596  minect = MIN(minect, ect);
2597  assert(maxlst < minect);
2598  }
2599 
2600  SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2601  assert(inferpeak >= maxlst);
2602  assert(inferpeak < minect);
2603 
2604  /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2605  if( relaxedpeak < inferpeak )
2606  {
2607  inferpeak = MAX(maxlst, relaxedpeak);
2608  }
2609  else if( relaxedpeak > inferpeak )
2610  {
2611  inferpeak = MIN(minect-1, relaxedpeak);
2612  }
2613  assert(inferpeak >= hmin);
2614  assert(inferpeak < hmax);
2615  assert(inferpeak >= maxlst);
2616  assert(inferpeak < minect);
2617 
2618  /* post all necessary bound changes */
2619  for( c = 0; c < ncands; ++c )
2620  {
2621  var = vars[cands[c]];
2622  assert(var != NULL);
2623 
2624  if( usebdwidening )
2625  {
2626  duration = durations[cands[c]];
2627 
2628  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2629  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2630  }
2631  else
2632  {
2633  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2634  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2635  }
2636 
2637  if( explanation != NULL )
2638  explanation[cands[c]] = TRUE;
2639  }
2640 
2641  SCIPfreeBufferArray(scip, &canddemands);
2642  SCIPfreeBufferArray(scip, &cands);
2643  }
2644 
2645  SCIPfreeBufferArray(scip, &reported);
2646 
2647  if( provedpeak != NULL )
2648  *provedpeak = inferpeak;
2649 
2650  return SCIP_OKAY;
2651 }
2652 
2653 #if 0
2654 /** repropagation of edge finding algorithm simplified version from Petr Vilim only a small subset is reported such that
2655  * energy in total and for bound change is enough
2656  */
2657 static
2658 SCIP_RETCODE resolvePropagationEdgeFinding(
2659  SCIP* scip, /**< SCIP data structure */
2660  int nvars, /**< number of start time variables (activities) */
2661  SCIP_VAR** vars, /**< array of start time variables */
2662  int* durations, /**< array of durations */
2663  int hmin, /**< left bound of time axis to be considered (including hmin) */
2664  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2665  SCIP_VAR* infervar, /**< variable whose bound change is to be explained */
2666  INFERINFO inferinfo, /**< inference info containing position of correct bdchgids */
2667  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2668  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2669  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2670  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2671  )
2672 {
2673  int est;
2674  int lct;
2675  int j;
2676 
2677  /* ???????????????????? do bound widening */
2678 
2679  assert(scip != NULL);
2680  assert(nvars > 0);
2681  assert(inferInfoGetProprule(inferinfo) == PROPRULE_2_EDGEFINDING);
2682 
2683  SCIPdebugMsg(scip, "repropagate edge-finding with short reasons for variable <%s>\n", SCIPvarGetName(infervar));
2684 
2685  if( boundtype == SCIP_BOUNDTYPE_LOWER )
2686  {
2687  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
2688  }
2689  else
2690  {
2691  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
2692  }
2693 
2694  est = inferInfoGetData1(inferinfo);
2695  lct = inferInfoGetData2(inferinfo);
2696  assert(est < lct);
2697 
2698  /* collect the energies of all variables in [est_omega, lct_omega] */
2699  for( j = 0; j < nvars; ++j )
2700  {
2701  SCIP_VAR* var;
2702  SCIP_Bool left;
2703  SCIP_Bool right;
2704  int duration;
2705  int lb;
2706  int ub;
2707 
2708  var = vars[j];
2709  assert(var != NULL);
2710 
2711  if( var == infervar )
2712  {
2713  if( explanation != NULL )
2714  explanation[j] = TRUE;
2715 
2716  continue;
2717  }
2718 
2719  lb = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
2720  ub = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2721 
2722  duration = durations[j];
2723  assert(duration > 0);
2724 
2725  /* in case the earliest start time is equal to hmin we have to also consider the jobs which run in that region
2726  * since we use adjusted jobs during the propagation
2727  */
2728  left = (est == hmin && lb + duration > hmin) || lb >= est;
2729 
2730  /* in case the latest completion time is equal to hmax we have to also consider the jobs which run in that region
2731  * since we use adjusted jobs during the propagation
2732  */
2733  right = (lct == hmax && ub < hmax) || ub + duration <= lct;
2734 
2735  /* store all jobs running in [est_omega; lct_omega] */
2736  if( left && right )
2737  {
2738  /* check if bound widening should be used */
2739  if( usebdwidening )
2740  {
2741  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(lct - duration)) );
2742  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(est)) );
2743  }
2744  else
2745  {
2746  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2747  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2748  }
2749 
2750  if( explanation != NULL )
2751  explanation[j] = TRUE;
2752  }
2753  }
2754 
2755  return SCIP_OKAY;
2756 }
2757 #endif
2758 
2759 /** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2760 static
2761 int computeOverlap(
2762  int begin, /**< begin of the times interval */
2763  int end, /**< end of time interval */
2764  int est, /**< earliest start time */
2765  int lst, /**< latest start time */
2766  int duration /**< duration of the job */
2767  )
2768 {
2769  int left;
2770  int right;
2771  int ect;
2772  int lct;
2773 
2774  ect = est + duration;
2775  lct = lst + duration;
2776 
2777  /* check if job runs completely within [begin,end) */
2778  if( lct <= end && est >= begin )
2779  return duration;
2780 
2781  assert(lst <= end && ect >= begin);
2782 
2783  left = ect - begin;
2784  assert(left > 0);
2785 
2786  right = end - lst;
2787  assert(right > 0);
2788 
2789  return MIN3(left, right, end - begin);
2790 }
2791 
2792 /** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2793  * reason
2794  *
2795  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2796  */
2797 static
2799  SCIP* scip, /**< SCIP data structure */
2800  int nvars, /**< number of start time variables (activities) */
2801  SCIP_VAR** vars, /**< array of start time variables */
2802  int* durations, /**< array of durations */
2803  int* demands, /**< array of demands */
2804  int capacity, /**< capacity of the cumulative condition */
2805  int begin, /**< begin of the time window */
2806  int end, /**< end of the time window */
2807  SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2808  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2809  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2810  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2811  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2812  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2813  )
2814 {
2815  int* locenergies;
2816  int* overlaps;
2817  int* idxs;
2818 
2819  int requiredenergy;
2820  int v;
2821 
2822  SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2823  SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2824  SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2825 
2826  /* energy which needs be explained */
2827  requiredenergy = (end - begin) * capacity;
2828 
2829  SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %d)\n", begin, end, capacity, requiredenergy);
2830 
2831  /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2832  * takes
2833  */
2834  for( v = 0; v < nvars; ++v )
2835  {
2836  SCIP_VAR* var;
2837  int glbenergy;
2838  int duration;
2839  int demand;
2840  int est;
2841  int lst;
2842 
2843  var = vars[v];
2844  assert(var != NULL);
2845 
2846  locenergies[v] = 0;
2847  overlaps[v] = 0;
2848  idxs[v] = v;
2849 
2850  demand = demands[v];
2851  assert(demand > 0);
2852 
2853  duration = durations[v];
2854  assert(duration > 0);
2855 
2856  /* check if the variable equals the inference variable (the one which was propagated) */
2857  if( infervar == var )
2858  {
2859  int overlap;
2860  int right;
2861  int left;
2862 
2863  assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2864 
2865  SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2866  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2867  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2868 
2869  /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2870  * which is necessary from the inference variable
2871  */
2872  if( boundtype == SCIP_BOUNDTYPE_UPPER )
2873  {
2874  int lct;
2875 
2876  /* get the latest start time of the infer start time variable before the propagation took place */
2877  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2878 
2879  /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2880  * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2881  * scheduled w.r.t. its latest start time
2882  */
2883  assert(lst < end);
2884 
2885  /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2886  * interval (before the propagation)
2887  */
2888  right = MIN3(end - lst, end - begin, duration);
2889 
2890  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2891  assert(right > 0);
2892 
2893  lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2894  assert(begin <= lct);
2895  assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
2896 
2897  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2898  left = MIN(lct - begin + 1, end - begin);
2899  assert(left > 0);
2900 
2901  /* compute the minimum overlap; */
2902  overlap = MIN(left, right);
2903  assert(overlap > 0);
2904  assert(overlap <= end - begin);
2905  assert(overlap <= duration);
2906 
2907  if( usebdwidening )
2908  {
2909  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2910  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2911  }
2912  else
2913  {
2914  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2915  }
2916  }
2917  else
2918  {
2919  int ect;
2920 
2921  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2922 
2923  /* get the earliest completion time of the infer start time variable before the propagation took place */
2924  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2925 
2926  /* the earliest start time of the inference start time variable before the propagation needs to be larger as
2927  * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
2928  * the job is scheduled w.r.t. its earliest start time
2929  */
2930  assert(ect > begin);
2931 
2932  /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
2933  * interval (before the propagation)
2934  */
2935  left = MIN3(ect - begin, end - begin, duration);
2936 
2937  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2938  assert(left > 0);
2939 
2940  est = SCIPconvertRealToInt(scip, relaxedbd);
2941  assert(end >= est);
2942  assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
2943 
2944  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2945  right = MIN(end - est + 1, end - begin);
2946  assert(right > 0);
2947 
2948  /* compute the minimum overlap */
2949  overlap = MIN(left, right);
2950  assert(overlap > 0);
2951  assert(overlap <= end - begin);
2952  assert(overlap <= duration);
2953 
2954  if( usebdwidening )
2955  {
2956  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
2957  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
2958  }
2959  else
2960  {
2961  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2962  }
2963  }
2964 
2965  /* subtract the amount of energy which is available due to the overlap of the inference start time */
2966  requiredenergy -= overlap * demand;
2967 
2968  if( explanation != NULL )
2969  explanation[v] = TRUE;
2970 
2971  continue;
2972  }
2973 
2974  /* global time points */
2975  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
2976  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2977 
2978  glbenergy = 0;
2979 
2980  /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
2981  * time window
2982  */
2983  if( est + duration > begin && lst < end )
2984  {
2985  /* evaluated global contribution */
2986  glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
2987 
2988  /* remove the globally available energy form the required energy */
2989  requiredenergy -= glbenergy;
2990 
2991  if( explanation != NULL )
2992  explanation[v] = TRUE;
2993  }
2994 
2995  /* local time points */
2996  est = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
2997  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2998 
2999  /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3000  * time window
3001  */
3002  if( est + duration > begin && lst < end )
3003  {
3004  overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3005 
3006  /* evaluated additionally local energy contribution */
3007  locenergies[v] = overlaps[v] * demand - glbenergy;
3008  assert(locenergies[v] >= 0);
3009  }
3010  }
3011 
3012  /* sort the variable contributions w.r.t. additional local energy contributions */
3013  SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3014 
3015  /* add local energy contributions until an overload is implied */
3016  for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3017  {
3018  SCIP_VAR* var;
3019  int duration;
3020  int overlap;
3021  int relaxlb;
3022  int relaxub;
3023  int idx;
3024 
3025  idx = idxs[v];
3026  assert(idx >= 0 && idx < nvars);
3027 
3028  var = vars[idx];
3029  assert(var != NULL);
3030  assert(var != infervar);
3031 
3032  duration = durations[idx];
3033  assert(duration > 0);
3034 
3035  overlap = overlaps[v];
3036  assert(overlap > 0);
3037 
3038  requiredenergy -= locenergies[v];
3039 
3040  if( requiredenergy < -1 )
3041  {
3042  int demand;
3043 
3044  demand = demands[idx];
3045  assert(demand > 0);
3046 
3047  overlap += (int)((requiredenergy + 1) / demand);
3048 
3049 #ifndef NDEBUG
3050  requiredenergy += locenergies[v];
3051  requiredenergy -= overlap * demand;
3052  assert(requiredenergy < 0);
3053 #endif
3054  }
3055  assert(overlap > 0);
3056 
3057  relaxlb = begin - duration + overlap;
3058  relaxub = end - overlap;
3059 
3060  SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3061  SCIPvarGetName(var),
3064  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var),
3065  relaxlb, relaxub, demands[idx], duration);
3066 
3067  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3068  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3069 
3070  if( explanation != NULL )
3071  explanation[idx] = TRUE;
3072  }
3073 
3074  assert(requiredenergy < 0);
3075 
3076  SCIPfreeBufferArray(scip, &idxs);
3077  SCIPfreeBufferArray(scip, &overlaps);
3078  SCIPfreeBufferArray(scip, &locenergies);
3079 
3080  return SCIP_OKAY;
3081 }
3082 
3083 /** resolve propagation w.r.t. the cumulative condition */
3084 static
3086  SCIP* scip, /**< SCIP data structure */
3087  int nvars, /**< number of start time variables (activities) */
3088  SCIP_VAR** vars, /**< array of start time variables */
3089  int* durations, /**< array of durations */
3090  int* demands, /**< array of demands */
3091  int capacity, /**< cumulative capacity */
3092  int hmin, /**< left bound of time axis to be considered (including hmin) */
3093  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3094  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3095  INFERINFO inferinfo, /**< the user information */
3096  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3097  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3098  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3099  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3100  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3101  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3102  )
3103 {
3104  switch( inferInfoGetProprule(inferinfo) )
3105  {
3106  case PROPRULE_1_CORETIMES:
3107  {
3108  int inferdemand;
3109  int inferduration;
3110  int inferpos;
3111  int inferpeak;
3112  int relaxedpeak;
3113  int provedpeak;
3114 
3115  /* get the position of the inferred variable in the vars array */
3116  inferpos = inferInfoGetData1(inferinfo);
3117  if( inferpos >= nvars || vars[inferpos] != infervar )
3118  {
3119  /* find inference variable in constraint */
3120  for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3121  {}
3122  }
3123  assert(inferpos < nvars);
3124  assert(vars[inferpos] == infervar);
3125 
3126  inferdemand = demands[inferpos];
3127  inferduration = durations[inferpos];
3128 
3129  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3130  {
3131  /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3132  * the inference variable
3133  */
3134  assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
3135 
3136  SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3137  SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
3138  SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3139 
3140  /* get the inference peak that the time point which lead to the that propagtion */
3141  inferpeak = inferInfoGetData2(inferinfo);
3142  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3143  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3144  */
3145  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3146  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) + inferduration;
3147 
3148  /* make sure that the relaxed peak is part of the effective horizon */
3149  relaxedpeak = MIN(relaxedpeak, hmax-1);
3150 
3151  /* make sure that relaxed peak is not larger than the infer peak
3152  *
3153  * This can happen in case the variable is not an active variable!
3154  */
3155  relaxedpeak = MAX(relaxedpeak, inferpeak);
3156  assert(relaxedpeak >= inferpeak);
3157  assert(relaxedpeak >= hmin);
3158  }
3159  else
3160  {
3161  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3162 
3163  SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3164  SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
3165  SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3166 
3167  /* get the time interval where the job could not be scheduled */
3168  inferpeak = inferInfoGetData2(inferinfo);
3169  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3170  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3171  */
3172  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3173  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) - 1;
3174 
3175  /* make sure that the relaxed peak is part of the effective horizon */
3176  relaxedpeak = MAX(relaxedpeak, hmin);
3177 
3178  /* make sure that relaxed peak is not larger than the infer peak
3179  *
3180  * This can happen in case the variable is not an active variable!
3181  */
3182  relaxedpeak = MIN(relaxedpeak, inferpeak);
3183  assert(relaxedpeak < hmax);
3184  }
3185 
3186  /* resolves the propagation of the core time algorithm */
3187  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3188  infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3189 
3190  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3191  {
3192  if( usebdwidening )
3193  {
3194  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3195  }
3196  else
3197  {
3198  /* old upper bound of variable itself is part of the explanation */
3199  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3200  }
3201  }
3202  else
3203  {
3204  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3205 
3206  if( usebdwidening )
3207  {
3208  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3209  }
3210  else
3211  {
3212  /* old lower bound of variable itself is part of the explanation */
3213  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3214  }
3215  }
3216 
3217  if( explanation != NULL )
3218  explanation[inferpos] = TRUE;
3219 
3220  break;
3221  }
3223  case PROPRULE_3_TTEF:
3224  {
3225  int begin;
3226  int end;
3227 
3228  begin = inferInfoGetData1(inferinfo);
3229  end = inferInfoGetData2(inferinfo);
3230  assert(begin < end);
3231 
3232  begin = MAX(begin, hmin);
3233  end = MIN(end, hmax);
3234 
3235  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3236  begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3237 
3238  break;
3239  }
3240 
3241  default:
3242  SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3243  SCIPABORT();
3244  return SCIP_INVALIDDATA; /*lint !e527*/
3245  }
3246 
3247  (*result) = SCIP_SUCCESS;
3248 
3249  return SCIP_OKAY;
3250 }
3251 
3252 /**@} */
3253 
3254 
3255 /**@name Enforcement methods
3256  *
3257  * @{
3258  */
3259 
3260 /** apply all fixings which are given by the alternative bounds */
3261 static
3263  SCIP* scip, /**< SCIP data structure */
3264  SCIP_VAR** vars, /**< array of active variables */
3265  int nvars, /**< number of active variables */
3266  int* alternativelbs, /**< alternative lower bounds */
3267  int* alternativeubs, /**< alternative lower bounds */
3268  int* downlocks, /**< number of constraints with down lock participating by the computation */
3269  int* uplocks, /**< number of constraints with up lock participating by the computation */
3270  SCIP_Bool* branched /**< pointer to store if a branching was applied */
3271  )
3272 {
3273  int v;
3274 
3275  for( v = 0; v < nvars; ++v )
3276  {
3277  SCIP_VAR* var;
3278  SCIP_Real objval;
3279 
3280  var = vars[v];
3281  assert(var != NULL);
3282 
3283  objval = SCIPvarGetObj(var);
3284 
3285  if( SCIPvarGetNLocksDown(var) == downlocks[v] && !SCIPisNegative(scip, objval) )
3286  {
3287  int ub;
3288 
3289  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3290 
3291  if( alternativelbs[v] <= ub )
3292  {
3293  SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3294  (*branched) = TRUE;
3295 
3296  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3297  SCIPvarGetLbLocal(var), alternativelbs[v]);
3298 
3299  return SCIP_OKAY;
3300  }
3301  }
3302 
3303  if( SCIPvarGetNLocksUp(var) == uplocks[v] && !SCIPisPositive(scip, objval) )
3304  {
3305  int lb;
3306 
3307  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3308 
3309  if( alternativeubs[v] >= lb )
3310  {
3311  SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3312  (*branched) = TRUE;
3313 
3314  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3315  alternativeubs[v], SCIPvarGetUbLocal(var));
3316 
3317  return SCIP_OKAY;
3318  }
3319  }
3320  }
3321 
3322  return SCIP_OKAY;
3323 }
3324 
3325 /** remove the capacity requirments for all job which start at the curtime */
3326 static
3328  SCIP_CONSDATA* consdata, /**< constraint data */
3329  int curtime, /**< current point in time */
3330  int* starttimes, /**< array of start times */
3331  int* startindices, /**< permutation with respect to the start times */
3332  int* freecapacity, /**< pointer to store the resulting free capacity */
3333  int* idx, /**< pointer to index in start time array */
3334  int nvars /**< number of vars in array of starttimes and startindices */
3335  )
3336 {
3337 
3338 #if defined SCIP_DEBUG && !defined NDEBUG
3339  int oldidx;
3340 
3341  assert(idx != NULL);
3342  oldidx = *idx;
3343 #else
3344  assert(idx != NULL);
3345 #endif
3346 
3347  assert(starttimes != NULL);
3348  assert(starttimes != NULL);
3349  assert(freecapacity != NULL);
3350  assert(starttimes[*idx] == curtime);
3351  assert(consdata->demands != NULL);
3352  assert(freecapacity != idx);
3353 
3354  /* subtract all capacity needed up to this point */
3355  (*freecapacity) -= consdata->demands[startindices[*idx]];
3356 
3357  while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3358  {
3359  ++(*idx);
3360  (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3361  assert(freecapacity != idx);
3362  }
3363 #ifdef SCIP_DEBUG
3364  assert(oldidx <= *idx);
3365 #endif
3366 }
3367 
3368 /** add the capacity requirments for all job which end at the curtime */
3369 static
3370 void addEndingJobDemands(
3371  SCIP_CONSDATA* consdata, /**< constraint data */
3372  int curtime, /**< current point in time */
3373  int* endtimes, /**< array of end times */
3374  int* endindices, /**< permutation with rspect to the end times */
3375  int* freecapacity, /**< pointer to store the resulting free capacity */
3376  int* idx, /**< pointer to index in end time array */
3377  int nvars /**< number of vars in array of starttimes and startindices */
3378  )
3379 {
3380 #if defined SCIP_DEBUG && !defined NDEBUG
3381  int oldidx;
3382  oldidx = *idx;
3383 #endif
3384 
3385  /* free all capacity usages of jobs the are no longer running */
3386  while( endtimes[*idx] <= curtime && *idx < nvars)
3387  {
3388  (*freecapacity) += consdata->demands[endindices[*idx]];
3389  ++(*idx);
3390  }
3391 
3392 #ifdef SCIP_DEBUG
3393  assert(oldidx <= *idx);
3394 #endif
3395 }
3396 
3397 /** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3398 static
3400  SCIP* scip, /**< SCIP data structure */
3401  SCIP_CONSDATA* consdata, /**< constraint handler data */
3402  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3403  int* timepoint /**< pointer to store the time point of the peak */
3404  )
3405 {
3406  int* starttimes; /* stores when each job is starting */
3407  int* endtimes; /* stores when each job ends */
3408  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3409  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3410 
3411  int nvars; /* number of activities for this constraint */
3412  int freecapacity; /* remaining capacity */
3413  int curtime; /* point in time which we are just checking */
3414  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3415 
3416  int hmin;
3417  int hmax;
3418 
3419  int j;
3420 
3421  assert(consdata != NULL);
3422 
3423  nvars = consdata->nvars;
3424  assert(nvars > 0);
3425 
3426  *timepoint = consdata->hmax;
3427 
3428  assert(consdata->vars != NULL);
3429 
3430  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3431  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3432  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3433  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3434 
3435  /* create event point arrays */
3436  createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3437  starttimes, endtimes, startindices, endindices);
3438 
3439  endindex = 0;
3440  freecapacity = consdata->capacity;
3441  hmin = consdata->hmin;
3442  hmax = consdata->hmax;
3443 
3444  /* check each startpoint of a job whether the capacity is kept or not */
3445  for( j = 0; j < nvars; ++j )
3446  {
3447  curtime = starttimes[j];
3448  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3449 
3450  if( curtime >= hmax )
3451  break;
3452 
3453  /* remove the capacity requirments for all job which start at the curtime */
3454  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3455 
3456  /* add the capacity requirments for all job which end at the curtime */
3457  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3458 
3459  assert(freecapacity <= consdata->capacity);
3460  assert(endindex <= nvars);
3461 
3462  /* endindex - points to the next job which will finish */
3463  /* j - points to the last job that has been released */
3464 
3465  /* if free capacity is smaller than zero, then add branching candidates */
3466  if( freecapacity < 0 && curtime >= hmin )
3467  {
3468  *timepoint = curtime;
3469  break;
3470  }
3471  } /*lint --e{850}*/
3472 
3473  /* free all buffer arrays */
3474  SCIPfreeBufferArray(scip, &endindices);
3475  SCIPfreeBufferArray(scip, &startindices);
3476  SCIPfreeBufferArray(scip, &endtimes);
3477  SCIPfreeBufferArray(scip, &starttimes);
3478 
3479  return SCIP_OKAY;
3480 }
3481 
3482 /** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3483 static
3485  SCIP* scip, /**< SCIP data structure */
3486  SCIP_CONS** conss, /**< constraints to be processed */
3487  int nconss, /**< number of constraints */
3488  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3489  int* nbranchcands /**< pointer to store the number of branching variables */
3490  )
3491 {
3492  SCIP_HASHTABLE* collectedvars;
3493  int c;
3494 
3495  assert(scip != NULL);
3496  assert(conss != NULL);
3497 
3498  /* create a hash table */
3499  SCIP_CALL( SCIPhashtableCreate(&collectedvars, SCIPblkmem(scip), SCIPgetNVars(scip),
3500  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3501 
3502  assert(scip != NULL);
3503  assert(conss != NULL);
3504 
3505  for( c = 0; c < nconss; ++c )
3506  {
3507  SCIP_CONS* cons;
3508  SCIP_CONSDATA* consdata;
3509 
3510  int curtime;
3511  int j;
3512 
3513  cons = conss[c];
3514  assert(cons != NULL);
3515 
3516  if( !SCIPconsIsActive(cons) )
3517  continue;
3518 
3519  consdata = SCIPconsGetData(cons);
3520  assert(consdata != NULL);
3521 
3522  /* get point in time when capacity is exceeded */
3523  SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3524 
3525  if( curtime < consdata->hmin || curtime >= consdata->hmax )
3526  continue;
3527 
3528  /* report all variables that are running at that point in time */
3529  for( j = 0; j < consdata->nvars; ++j )
3530  {
3531  SCIP_VAR* var;
3532  int lb;
3533  int ub;
3534 
3535  var = consdata->vars[j];
3536  assert(var != NULL);
3537 
3538  /* check if the variable was already added */
3539  if( SCIPhashtableExists(collectedvars, (void*)var) )
3540  continue;
3541 
3542  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3543  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3544 
3545  if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3546  {
3547  SCIP_Real solval;
3548  SCIP_Real score;
3549 
3550  solval = SCIPgetSolVal(scip, sol, var);
3551  score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3552 
3553  SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3554  SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3555  (*nbranchcands)++;
3556 
3557  SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3558  }
3559  }
3560  }
3561 
3562  SCIPhashtableFree(&collectedvars);
3563 
3564  SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3565 
3566  return SCIP_OKAY;
3567 }
3568 
3569 /** enforcement of an LP, pseudo, or relaxation solution */
3570 static
3572  SCIP* scip, /**< SCIP data structure */
3573  SCIP_CONS** conss, /**< constraints to be processed */
3574  int nconss, /**< number of constraints */
3575  SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
3576  SCIP_Bool branch, /**< should branching candidates be collected */
3577  SCIP_RESULT* result /**< pointer to store the result */
3578  )
3579 {
3580  if( branch )
3581  {
3582  int nbranchcands;
3583 
3584  nbranchcands = 0;
3585  SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3586 
3587  if( nbranchcands > 0 )
3588  (*result) = SCIP_INFEASIBLE;
3589  }
3590  else
3591  {
3592  SCIP_Bool violated;
3593  int c;
3594 
3595  violated = FALSE;
3596 
3597  /* first check if a constraints is violated */
3598  for( c = 0; c < nconss && !violated; ++c )
3599  {
3600  SCIP_CONS* cons;
3601 
3602  cons = conss[c];
3603  assert(cons != NULL);
3604 
3605  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3606  }
3607 
3608  if( violated )
3609  (*result) = SCIP_INFEASIBLE;
3610  }
3611 
3612  return SCIP_OKAY;
3613 }
3614 
3615 /**@} */
3616 
3617 /**@name Propagation
3618  *
3619  * @{
3620  */
3621 
3622 /** check if cumulative constraint is independently of all other constraints */
3623 static
3625  SCIP* scip, /**< SCIP data structure */
3626  SCIP_CONS* cons /**< cumulative constraint */
3627  )
3628 {
3629  SCIP_CONSDATA* consdata;
3630  SCIP_VAR** vars;
3631  SCIP_Bool* downlocks;
3632  SCIP_Bool* uplocks;
3633  int nvars;
3634  int v;
3635 
3636  consdata = SCIPconsGetData(cons);
3637  assert(consdata != NULL);
3638 
3639  nvars = consdata->nvars;
3640  vars = consdata->vars;
3641  downlocks = consdata->downlocks;
3642  uplocks = consdata->uplocks;
3643 
3644  /* check if the cumulative constraint has the only locks on the involved variables */
3645  for( v = 0; v < nvars; ++v )
3646  {
3647  SCIP_VAR* var;
3648 
3649  var = vars[v];
3650  assert(var != NULL);
3651 
3652  if( SCIPvarGetNLocksDown(var) > (int)downlocks[v] || SCIPvarGetNLocksUp(var) > (int)uplocks[v] )
3653  return FALSE;
3654  }
3655 
3656  return TRUE;
3657 }
3658 
3659 /** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3660  * (dual reductions)
3661  */
3662 static
3664  SCIP* scip, /**< SCIP data structure */
3665  SCIP_CONS* cons, /**< cumulative constraint */
3666  SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3667  int* nchgbds, /**< pointer to store the number changed variable bounds */
3668  int* nfixedvars, /**< pointer to count number of fixings */
3669  int* ndelconss, /**< pointer to count number of deleted constraints */
3670  SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3671  SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3672  )
3673 {
3674  SCIP_CONSDATA* consdata;
3675  SCIP_VAR** vars;
3676  SCIP_Real* objvals;
3677  SCIP_Real* lbs;
3678  SCIP_Real* ubs;
3679  SCIP_Real timelimit;
3680  SCIP_Real memorylimit;
3681  SCIP_Bool solved;
3682  SCIP_Bool error;
3683 
3684  int ncheckconss;
3685  int nvars;
3686  int v;
3687 
3688  assert(scip != NULL);
3689  assert(!SCIPconsIsModifiable(cons));
3690  assert(SCIPgetNConss(scip) > 0);
3691 
3692  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3693  * would/could end in an implication which can lead to cutoff of the/all optimal solution
3694  */
3695  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
3696  return SCIP_OKAY;
3697 
3698  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3699  * use the locks to decide for a dual reduction using this constraint;
3700  */
3701  if( !SCIPconsIsChecked(cons) )
3702  return SCIP_OKAY;
3703 
3704  ncheckconss = SCIPgetNCheckConss(scip);
3705 
3706  /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3707  * presolved problem do nothing execpt to change the parameter settings
3708  */
3709  if( ncheckconss == 1 )
3710  {
3711  /* shrink the minimal maximum value for the conflict length */
3712  SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3713 
3714  /* use only first unique implication point */
3715  SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3716 
3717  /* do not use reconversion conflicts */
3718  SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3719 
3720  /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3721  SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3722 
3723  /* increase the number of conflicts which induce a restart */
3724  SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3725 
3726  /* weight the variable which made into a conflict */
3727  SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3728 
3729  /* do not check pseudo solution (for performance reasons) */
3730  SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3731 
3732  /* use value based history to detect a reasonable branching point */
3733  SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3734 
3735  /* turn of LP relaxation */
3736  SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3737 
3738  /* prefer the down branch in case the value based history does not suggest something */
3739  SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3740 
3741  /* accept any bound change */
3742  SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3743 
3744  /* allow for at most 10 restart, after that the value based history should be reliable */
3745  SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3746 
3747  /* set priority for depth first search to highest possible value */
3748  SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3749 
3750  return SCIP_OKAY;
3751  }
3752 
3753  consdata = SCIPconsGetData(cons);
3754  assert(consdata != NULL);
3755 
3756  /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3757  * fail on the first place
3758  */
3759  if( consdata->triedsolving )
3760  return SCIP_OKAY;
3761 
3762  /* check if constraint is independently */
3763  if( !isConsIndependently(scip, cons) )
3764  return SCIP_OKAY;
3765 
3766  /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3767  * constraint is deleted; otherwise, we want to ensure that we do not try that again
3768  */
3769  consdata->triedsolving = TRUE;
3770 
3771  SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3772  SCIPconsGetName(cons), SCIPgetNVars(scip), SCIPgetNConss(scip));
3773  SCIPdebugPrintCons(scip, cons, NULL);
3774 
3775  nvars = consdata->nvars;
3776  vars = consdata->vars;
3777 
3778  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3779  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3780  SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3781 
3782  for( v = 0; v < nvars; ++v )
3783  {
3784  SCIP_VAR* var;
3785 
3786  /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3787  * array
3788  */
3789  var = vars[v];
3790  assert(var != NULL);
3791 
3792  lbs[v] = SCIPvarGetLbLocal(var);
3793  ubs[v] = SCIPvarGetUbLocal(var);
3794 
3795  objvals[v] = SCIPvarGetObj(var);
3796  }
3797 
3798  /* check whether there is enough time and memory left */
3799  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3800  if( !SCIPisInfinity(scip, timelimit) )
3801  timelimit -= SCIPgetSolvingTime(scip);
3802  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3803 
3804  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3805  if( !SCIPisInfinity(scip, memorylimit) )
3806  {
3807  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3808  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3809  }
3810 
3811  /* solve the cumulative condition separately */
3812  SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3813  consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3814 
3815  if( !(*cutoff) && !(*unbounded) && !error )
3816  {
3817  SCIP_Bool infeasible;
3818  SCIP_Bool tightened;
3819  SCIP_Bool allfixed;
3820 
3821  allfixed = TRUE;
3822 
3823  for( v = 0; v < nvars; ++v )
3824  {
3825  /* check if variable is fixed */
3826  if( lbs[v] + 0.5 > ubs[v] )
3827  {
3828  SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3829  assert(!infeasible);
3830 
3831  if( tightened )
3832  {
3833  (*nfixedvars)++;
3834  consdata->triedsolving = FALSE;
3835  }
3836  }
3837  else
3838  {
3839  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3840  assert(!infeasible);
3841 
3842  if( tightened )
3843  {
3844  (*nchgbds)++;
3845  consdata->triedsolving = FALSE;
3846  }
3847 
3848  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3849  assert(!infeasible);
3850 
3851  if( tightened )
3852  {
3853  (*nchgbds)++;
3854  consdata->triedsolving = FALSE;
3855  }
3856 
3857  allfixed = FALSE;
3858  }
3859  }
3860 
3861  /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3862  if( allfixed )
3863  {
3864  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3865  (*ndelconss)++;
3866  }
3867  }
3868 
3869  SCIPfreeBufferArray(scip, &objvals);
3870  SCIPfreeBufferArray(scip, &ubs);
3871  SCIPfreeBufferArray(scip, &lbs);
3872 
3873  return SCIP_OKAY;
3874 }
3875 
3876 /** start conflict analysis to analysis the core insertion which is infeasible */
3877 static
3879  SCIP* scip, /**< SCIP data structure */
3880  int nvars, /**< number of start time variables (activities) */
3881  SCIP_VAR** vars, /**< array of start time variables */
3882  int* durations, /**< array of durations */
3883  int* demands, /**< array of demands */
3884  int capacity, /**< cumulative capacity */
3885  int hmin, /**< left bound of time axis to be considered (including hmin) */
3886  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3887  SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3888  int inferduration, /**< duration of the start time variable */
3889  int inferdemand, /**< demand of the start time variable */
3890  int inferpeak, /**< profile preak which causes the infeasibilty */
3891  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3892  SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3893  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3894  )
3895 {
3896  SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3897  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3898  SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3899 
3900  /* initialize conflict analysis if conflict analysis is applicable */
3902  {
3904 
3905  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3906  infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3907 
3908  SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3909 
3910  /* add both bound of the inference variable since these biuld the core which we could not inserted */
3911  if( usebdwidening )
3912  {
3913  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
3914  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
3915  }
3916  else
3917  {
3918  SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
3919  SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
3920  }
3921 
3922  *initialized = TRUE;
3923  }
3924 
3925  return SCIP_OKAY;
3926 }
3927 
3928 /** We are using the core resource profile which contains all core except the one of the start time variable which we
3929  * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
3930  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
3931  * analysis
3932  */
3933 static
3935  SCIP* scip, /**< SCIP data structure */
3936  int nvars, /**< number of start time variables (activities) */
3937  SCIP_VAR** vars, /**< array of start time variables */
3938  int* durations, /**< array of durations */
3939  int* demands, /**< array of demands */
3940  int capacity, /**< cumulative capacity */
3941  int hmin, /**< left bound of time axis to be considered (including hmin) */
3942  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3943  SCIP_CONS* cons, /**< constraint which is propagated */
3944  SCIP_PROFILE* profile, /**< resource profile */
3945  int idx, /**< position of the variable to propagate */
3946  int* nchgbds, /**< pointer to store the number of bound changes */
3947  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3948  SCIP_Bool* initialized, /**< was conflict analysis initialized */
3949  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3950  SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
3951  )
3952 {
3953  SCIP_VAR* var;
3954  int ntimepoints;
3955  int duration;
3956  int demand;
3957  int peak;
3958  int newlb;
3959  int est;
3960  int lst;
3961  int pos;
3962 
3963  var = vars[idx];
3964  assert(var != NULL);
3965 
3966  duration = durations[idx];
3967  assert(duration > 0);
3968 
3969  demand = demands[idx];
3970  assert(demand > 0);
3971 
3972  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3973  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3974  ntimepoints = SCIPprofileGetNTimepoints(profile);
3975 
3976  /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
3977  * load which we have at the earliest start time (lower bound)
3978  */
3979  (void) SCIPprofileFindLeft(profile, est, &pos);
3980 
3981  SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
3982 
3983  /* we now trying to move the earliest start time in steps of at most "duration" length */
3984  do
3985  {
3986  INFERINFO inferinfo;
3987  SCIP_Bool tightened;
3988  int ect;
3989 
3990 #ifndef NDEBUG
3991  {
3992  /* in debug mode we check that we adjust the search position correctly */
3993  int tmppos;
3994 
3995  (void)SCIPprofileFindLeft(profile, est, &tmppos);
3996  assert(pos == tmppos);
3997  }
3998 #endif
3999  ect = est + duration;
4000  peak = -1;
4001 
4002  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4003  * want a peak which is closest to the earliest completion time
4004  */
4005  do
4006  {
4007  /* check if the profile load conflicts with the demand of the start time variable */
4008  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4009  peak = pos;
4010 
4011  pos++;
4012  }
4013  while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4014 
4015  /* if we found no peak that means current the job could be scheduled at its earliest start time without
4016  * conflicting to the core resource profile
4017  */
4018  if( peak == -1 )
4019  break;
4020 
4021  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4022  * profile. That means we have to move it to the next time point in the resource profile but at most to the
4023  * earliest completion time (the remaining move will done in the next loop)
4024  */
4025  newlb = SCIPprofileGetTime(profile, peak+1);
4026  newlb = MIN(newlb, ect);
4027 
4028  /* if the earliest start time is greater than the lst we detected an infeasibilty */
4029  if( newlb > lst )
4030  {
4031  SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4032 
4033  /* use conflict analysis to analysis the core insertion which was infeasible */
4034  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4035  var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4036 
4037  if( explanation != NULL )
4038  explanation[idx] = TRUE;
4039 
4040  *infeasible = TRUE;
4041 
4042  break;
4043  }
4044 
4045  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4046  * bound change
4047  */
4048  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4049 
4050  /* perform the bound lower bound change */
4051  SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4052  assert(tightened);
4053  assert(!(*infeasible));
4054 
4055  SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4056  (*nchgbds)++;
4057 
4058  /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4060 
4061  /* adjust the earliest start time
4062  *
4063  * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4064  * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4065  * involved.
4066  */
4067  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4068  assert(est >= newlb);
4069 
4070  /* adjust the search position for the resource profile for the next step */
4071  if( est == SCIPprofileGetTime(profile, peak+1) )
4072  pos = peak + 1;
4073  else
4074  pos = peak;
4075  }
4076  while( est < lst );
4077 
4078  return SCIP_OKAY;
4079 }
4080 
4081 /** We are using the core resource profile which contains all core except the one of the start time variable which we
4082  * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4083  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4084  * analysis
4085  */
4086 static
4088  SCIP* scip, /**< SCIP data structure */
4089  SCIP_VAR* var, /**< start time variable to propagate */
4090  int duration, /**< duration of the job */
4091  int demand, /**< demand of the job */
4092  int capacity, /**< cumulative capacity */
4093  SCIP_CONS* cons, /**< constraint which is propagated */
4094  SCIP_PROFILE* profile, /**< resource profile */
4095  int idx, /**< position of the variable to propagate */
4096  int* nchgbds /**< pointer to store the number of bound changes */
4097  )
4098 {
4099  int ntimepoints;
4100  int newub;
4101  int peak;
4102  int pos;
4103  int est;
4104  int lst;
4105  int lct;
4106 
4107  assert(var != NULL);
4108  assert(duration > 0);
4109  assert(demand > 0);
4110 
4111  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4112  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4113 
4114  /* in case the start time variable is fixed do nothing */
4115  if( est == lst )
4116  return SCIP_OKAY;
4117 
4118  ntimepoints = SCIPprofileGetNTimepoints(profile);
4119 
4120  lct = lst + duration;
4121 
4122  /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4123  * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4124  * position gives us the load which we have at the latest completion time minus one
4125  */
4126  (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4127 
4128  SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4129  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
4130 
4131  if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4132  return SCIP_OKAY;
4133 
4134  /* we now trying to move the latest start time in steps of at most "duration" length */
4135  do
4136  {
4137  INFERINFO inferinfo;
4138  SCIP_Bool tightened;
4139  SCIP_Bool infeasible;
4140 
4141  peak = -1;
4142 
4143 #ifndef NDEBUG
4144  {
4145  /* in debug mode we check that we adjust the search position correctly */
4146  int tmppos;
4147 
4148  (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4149  assert(pos == tmppos);
4150  }
4151 #endif
4152 
4153  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4154  * want a peak which is closest to the latest start time
4155  */
4156  do
4157  {
4158  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4159  peak = pos;
4160 
4161  pos--;
4162  }
4163  while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4164 
4165  /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4166  * to the core resource profile
4167  */
4168  if( peak == -1 )
4169  break;
4170 
4171  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4172  * profile. That means the job has be done until that point. Hence that gives us the latest completion
4173  * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4174  * doing in the next loop)
4175  */
4176  newub = SCIPprofileGetTime(profile, peak);
4177  newub = MAX(newub, lst) - duration;
4178  assert(newub >= est);
4179 
4180  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4181  * bound change
4182  */
4183  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4184 
4185  /* perform the bound upper bound change */
4186  SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4187  assert(tightened);
4188  assert(!infeasible);
4189 
4190  SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4191  (*nchgbds)++;
4192 
4193  /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4195 
4196  /* adjust the latest start and completion time
4197  *
4198  * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4199  * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4200  * involved.
4201  */
4202  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4203  assert(lst <= newub);
4204  lct = lst + duration;
4205 
4206  /* adjust the search position for the resource profile for the next step */
4207  if( SCIPprofileGetTime(profile, peak) == lct )
4208  pos = peak - 1;
4209  else
4210  pos = peak;
4211  }
4212  while( est < lst );
4213 
4214  return SCIP_OKAY;
4215 }
4216 
4217 /** compute for the different earliest start and latest completion time the core energy of the corresponding time
4218  * points
4219  */
4220 static
4222  SCIP* scip, /**< SCIP data structure */
4223  SCIP_PROFILE* profile, /**< core profile */
4224  int nvars, /**< number of start time variables (activities) */
4225  int* ests, /**< array of sorted earliest start times */
4226  int* lcts, /**< array of sorted latest completion times */
4227  int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4228  int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4229  )
4230 {
4231  int ntimepoints;
4232  int energy;
4233  int t;
4234  int v;
4235 
4236  ntimepoints = SCIPprofileGetNTimepoints(profile);
4237  t = ntimepoints - 1;
4238  energy = 0;
4239 
4240  /* compute core energy after the earliest start time of each job */
4241  for( v = nvars-1; v >= 0; --v )
4242  {
4243  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4244  {
4245  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4246  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4247  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4248  t--;
4249  }
4250  assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4251 
4252  /* maybe ests[j] is in-between two timepoints */
4253  if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4254  {
4255  assert(t > 0);
4256  coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4257  }
4258  else
4259  coreEnergyAfterEst[v] = energy;
4260  }
4261 
4262  t = ntimepoints - 1;
4263  energy = 0;
4264 
4265  /* compute core energy after the latest completion time of each job */
4266  for( v = nvars-1; v >= 0; --v )
4267  {
4268  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4269  {
4270  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4271  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4272  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4273  t--;
4274  }
4275  assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4276 
4277  /* maybe lcts[j] is in-between two timepoints */
4278  if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4279  {
4280  assert(t > 0);
4281  coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4282  }
4283  else
4284  coreEnergyAfterLct[v] = energy;
4285  }
4286 
4287  return SCIP_OKAY;
4288 }
4289 
4290 /** collect earliest start times, latest completion time, and free energy contributions */
4291 static
4292 void collectDataTTEF(
4293  SCIP* scip, /**< SCIP data structure */
4294  int nvars, /**< number of start time variables (activities) */
4295  SCIP_VAR** vars, /**< array of start time variables */
4296  int* durations, /**< array of durations */
4297  int* demands, /**< array of demands */
4298  int hmin, /**< left bound of time axis to be considered (including hmin) */
4299  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4300  int* permests, /**< array to store the variable positions */
4301  int* ests, /**< array to store earliest start times */
4302  int* permlcts, /**< array to store the variable positions */
4303  int* lcts, /**< array to store latest completion times */
4304  int* ects, /**< array to store earliest completion times of the flexible part of the job */
4305  int* lsts, /**< array to store latest start times of the flexible part of the job */
4306  int* flexenergies /**< array to store the flexible energies of each job */
4307  )
4308 {
4309  int v;
4310 
4311  for( v = 0; v < nvars; ++ v)
4312  {
4313  int duration;
4314  int leftadjust;
4315  int rightadjust;
4316  int core;
4317  int est;
4318  int lct;
4319  int ect;
4320  int lst;
4321 
4322  duration = durations[v];
4323  assert(duration > 0);
4324 
4325  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4326  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
4327  ect = est + duration;
4328  lct = lst + duration;
4329 
4330  ests[v] = est;
4331  lcts[v] = lct;
4332  permests[v] = v;
4333  permlcts[v] = v;
4334 
4335  /* compute core time window which lies within the effective horizon */
4336  core = computeCoreWithInterval(hmin, hmax, ect, lst);
4337 
4338  /* compute the number of time steps the job could run before the effective horizon */
4339  leftadjust = MAX(0, hmin - est);
4340 
4341  /* compute the number of time steps the job could run after the effective horizon */
4342  rightadjust = MAX(0, lct - hmax);
4343 
4344  /* compute for each job the energy which is flexible; meaning not part of the core */
4345  flexenergies[v] = duration - leftadjust - rightadjust - core;
4346  flexenergies[v] = MAX(0, flexenergies[v]);
4347  flexenergies[v] *= demands[v];
4348  assert(flexenergies[v] >= 0);
4349 
4350  /* the earliest completion time of the flexible energy */
4351  ects[v] = MIN(ect, lst);
4352 
4353  /* the latest start time of the flexible energy */
4354  lsts[v] = MAX(ect, lst);
4355  }
4356 }
4357 
4358 /** try to tighten the lower bound of the given variable */
4359 static
4361  SCIP* scip, /**< SCIP data structure */
4362  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4363  int nvars, /**< number of start time variables (activities) */
4364  SCIP_VAR** vars, /**< array of start time variables */
4365  int* durations, /**< array of durations */
4366  int* demands, /**< array of demands */
4367  int capacity, /**< cumulative capacity */
4368  int hmin, /**< left bound of time axis to be considered (including hmin) */
4369  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4370  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4371  int duration, /**< duration of the job */
4372  int demand, /**< demand of the job */
4373  int est, /**< earliest start time of the job */
4374  int ect, /**< earliest completion time of the flexible part of the job */
4375  int lct, /**< latest completion time of the job */
4376  int begin, /**< begin of the time window under investigation */
4377  int end, /**< end of the time window under investigation */
4378  int energy, /**< available energy for the flexible part of the hob within the time window */
4379  int* bestlb, /**< pointer to strope the best lower bound change */
4380  int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4381  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4382  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4383  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4384  )
4385 {
4386  int newlb;
4387 
4388  assert(begin >= hmin);
4389  assert(end <= hmax);
4390 
4391  /* check if the time-table edge-finding should infer bounds */
4392  if( !conshdlrdata->ttefinfer )
4393  return SCIP_OKAY;
4394 
4395  /* if the job can be processed completely before or after the time window, nothing can be tightened */
4396  if( est >= end || ect <= begin )
4397  return SCIP_OKAY;
4398 
4399  /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4400  * skip since the overload check will do the job
4401  */
4402  if( est >= begin && ect <= end )
4403  return SCIP_OKAY;
4404 
4405  /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4406  * earliest start time
4407  */
4408  if( energy >= demand * (MAX(begin, est) - MIN(end, ect)) )
4409  return SCIP_OKAY;
4410 
4411  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4412  * present; therefore, we need to add the core;
4413  *
4414  * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4415  * compute the earliest completion time of the (whole) job
4416  */
4417  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4418 
4419  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4420  *
4421  * @note we can round down the compute duration w.r.t. the available energy
4422  */
4423  newlb = end - energy / demand;
4424 
4425  /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4426  * bound (latest start time); meaning it is not possible to schedule the job
4427  */
4428  if( newlb > lct - duration )
4429  {
4430  /* initialize conflict analysis if conflict analysis is applicable */
4432  {
4433  SCIP_Real relaxedbd;
4434 
4435  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4436 
4437  /* it is enough to overshoot the upper bound of the variable by one */
4438  relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4439 
4440  /* initialize conflict analysis */
4442 
4443  /* added to upper bound (which was overcut be new lower bound) of the variable */
4444  SCIP_CALL( SCIPaddConflictUb(scip, var, NULL) );
4445 
4446  /* analyze the infeasible */
4447  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4448  begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4449 
4450  (*initialized) = TRUE;
4451  }
4452 
4453  (*cutoff) = TRUE;
4454  }
4455  else if( newlb > (*bestlb) )
4456  {
4457  INFERINFO inferinfo;
4458 
4459  assert(newlb > begin);
4460 
4461  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4462 
4463  /* construct inference information */
4464  (*inferinfos) = inferInfoToInt(inferinfo);
4465  (*bestlb) = newlb;
4466  }
4467 
4468  return SCIP_OKAY;
4469 }
4470 
4471 /** try to tighten the upper bound of the given variable */
4472 static
4474  SCIP* scip, /**< SCIP data structure */
4475  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4476  int nvars, /**< number of start time variables (activities) */
4477  SCIP_VAR** vars, /**< array of start time variables */
4478  int* durations, /**< array of durations */
4479  int* demands, /**< array of demands */
4480  int capacity, /**< cumulative capacity */
4481  int hmin, /**< left bound of time axis to be considered (including hmin) */
4482  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4483  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4484  int duration, /**< duration of the job */
4485  int demand, /**< demand of the job */
4486  int est, /**< earliest start time of the job */
4487  int lst, /**< latest start time of the flexible part of the job */
4488  int lct, /**< latest completion time of the job */
4489  int begin, /**< begin of the time window under investigation */
4490  int end, /**< end of the time window under investigation */
4491  int energy, /**< available energy for the flexible part of the hob within the time window */
4492  int* bestub, /**< pointer to strope the best upper bound change */
4493  int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4494  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4495  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4496  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4497  )
4498 {
4499  int newub;
4500 
4501  assert(begin >= hmin);
4502  assert(end <= hmax);
4503  assert(est < begin);
4504 
4505  /* check if the time-table edge-finding should infer bounds */
4506  if( !conshdlrdata->ttefinfer )
4507  return SCIP_OKAY;
4508 
4509  /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4510  if( lst >= end || lct <= begin )
4511  return SCIP_OKAY;
4512 
4513  /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4514  * skip since the overload check will do the job
4515  */
4516  if( lst >= begin && lct <= end )
4517  return SCIP_OKAY;
4518 
4519  /* check if the available energy in the time window is to small to handle the flexible part of the job */
4520  if( energy >= demand * (MIN(end, lct) - MAX(begin, lst)) )
4521  return SCIP_OKAY;
4522 
4523  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4524  * present; therefore, we need to add the core;
4525  *
4526  * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4527  * latest start of the (whole) job
4528  */
4529  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4530  assert(energy >= 0);
4531 
4532  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4533  *
4534  * @note we can round down the compute duration w.r.t. the available energy
4535  */
4536  assert(demand > 0);
4537  newub = begin - duration + energy / demand;
4538 
4539  /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4540  * bound (earliest start time); meaning it is not possible to schedule the job
4541  */
4542  if( newub < est )
4543  {
4544  /* initialize conflict analysis if conflict analysis is applicable */
4546  {
4547  SCIP_Real relaxedbd;
4548 
4549  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4550 
4551  /* it is enough to undershoot the lower bound of the variable by one */
4552  relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4553 
4554  /* initialize conflict analysis */
4556 
4557  /* added to lower bound (which was undercut be new upper bound) of the variable */
4558  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
4559 
4560  /* analyze the infeasible */
4561  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4562  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4563 
4564  (*initialized) = TRUE;
4565  }
4566 
4567  (*cutoff) = TRUE;
4568  }
4569  else if( newub < (*bestub) )
4570  {
4571  INFERINFO inferinfo;
4572 
4573  assert(newub < begin);
4574 
4575  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4576 
4577  /* construct inference information */
4578  (*inferinfos) = inferInfoToInt(inferinfo);
4579  (*bestub) = newub;
4580  }
4581 
4582  return SCIP_OKAY;
4583 }
4584 
4585 /** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4586 static
4588  SCIP* scip, /**< SCIP data structure */
4589  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4590  int nvars, /**< number of start time variables (activities) */
4591  SCIP_VAR** vars, /**< array of start time variables */
4592  int* durations, /**< array of durations */
4593  int* demands, /**< array of demands */
4594  int capacity, /**< cumulative capacity */
4595  int hmin, /**< left bound of time axis to be considered (including hmin) */
4596  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4597  int* newlbs, /**< array to buffer new lower bounds */
4598  int* newubs, /**< array to buffer new upper bounds */
4599  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4600  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4601  int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4602  int* flexenergies, /**< array of flexible energies in the same order as the variables */
4603  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4604  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4605  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4606  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4607  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4608  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4609  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4610  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4611  )
4612 {
4613  int coreEnergyAfterEnd;
4614  int maxavailable;
4615  int minavailable;
4616  int totalenergy;
4617  int nests;
4618  int est;
4619  int lct;
4620  int start;
4621  int end;
4622  int v;
4623 
4624  est = INT_MAX;
4625  lct = INT_MIN;
4626 
4627  /* compute earliest start and latest completion time of all jobs */
4628  for( v = 0; v < nvars; ++v )
4629  {
4630  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4631  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4632 
4633  est = MIN(est, start);
4634  lct = MAX(lct, end);
4635  }
4636 
4637  /* adjust the effective time horizon */
4638  hmin = MAX(hmin, est);
4639  hmax = MIN(hmax, lct);
4640 
4641  end = hmax + 1;
4642  coreEnergyAfterEnd = -1;
4643 
4644  maxavailable = (hmax - hmin) * capacity;
4645  minavailable = maxavailable;
4646  totalenergy = computeTotalEnergy(durations, demands, nvars);
4647 
4648  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4649  if( (lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4650  return SCIP_OKAY;
4651 
4652  nests = nvars;
4653 
4654  /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4655  * times define the end of the time interval under investigation
4656  */
4657  for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4658  {
4659  int flexenergy;
4660  int minbegin;
4661  int lbenergy;
4662  int lbcand;
4663  int i;
4664 
4665  lct = lcts[v];
4666 
4667  /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4668  * infinity capacity is available; hence we skip that
4669  */
4670  if( lct > hmax )
4671  continue;
4672 
4673  /* if the latest completion time is smaller then hmin we have to stop */
4674  if( lct <= hmin )
4675  {
4676  assert(v == 0 || lcts[v-1] <= lcts[v]);
4677  break;
4678  }
4679 
4680  /* if the latest completion time equals to previous end time, we can continue since this particular interval
4681  * induced by end was just analyzed
4682  */
4683  if( lct == end )
4684  continue;
4685 
4686  assert(lct < end);
4687 
4688  /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4689  * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4690  * free energy; if so it means that in the next iterate the free-energy cannot be negative
4691  */
4692  if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4693  {
4694  int freeenergy;
4695 
4696  assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4697  assert(coreEnergyAfterEnd >= 0);
4698 
4699  /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4700  freeenergy = capacity * (end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4701 
4702  if( freeenergy <= minavailable )
4703  {
4704  SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%d>, free energy <%d>)\n", lct, minavailable, freeenergy);
4705  continue;
4706  }
4707  }
4708 
4709  SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4710 
4711  end = lct;
4712  coreEnergyAfterEnd = coreEnergyAfterLct[v];
4713 
4714  flexenergy = 0;
4715  minavailable = maxavailable;
4716  minbegin = hmax;
4717  lbcand = -1;
4718  lbenergy = 0;
4719 
4720  /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4721  * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4722  * wider
4723  */
4724  for( i = nests-1; i >= 0; --i )
4725  {
4726  SCIP_VAR* var;
4727  int freeenergy;
4728  int duration;
4729  int demand;
4730  int begin;
4731  int idx;
4732  int lst;
4733 
4734  idx = perm[i];
4735  assert(idx >= 0);
4736  assert(idx < nvars);
4737  assert(!(*cutoff));
4738 
4739  /* the earliest start time of the job */
4740  est = ests[i];
4741 
4742  /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4743  * latest completion times (which define end) are scant in non-increasing order
4744  */
4745  if( end <= est )
4746  {
4747  nests--;
4748  continue;
4749  }
4750 
4751  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4752  * current ending time
4753  */
4754  if( (end - est) * capacity >= totalenergy )
4755  break;
4756 
4757  var = vars[idx];
4758  assert(var != NULL);
4759 
4760  duration = durations[idx];
4761  assert(duration > 0);
4762 
4763  demand = demands[idx];
4764  assert(demand > 0);
4765 
4766  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4767 
4768  /* the latest start time of the free part of the job */
4769  lst = lsts[idx];
4770 
4771  /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4772  * investigation; hence the overload check will do the the job
4773  */
4774  assert(est <= minbegin);
4775  if( minavailable < maxavailable && est < minbegin )
4776  {
4777  assert(!(*cutoff));
4778 
4779  /* try to tighten the upper bound */
4780  SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4781  var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4782  initialized, explanation, cutoff) );
4783 
4784  if( *cutoff )
4785  break;
4786  }
4787 
4788  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4789  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4790 
4791  begin = est;
4792  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4793 
4794  /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4795  * free energy
4796  */
4797  if( begin < hmin )
4798  break;
4799 
4800  /* compute the contribution to the flexible energy */
4801  if( lct <= end )
4802  {
4803  /* if the jobs has to finish before the end, all the energy has to be scheduled */
4804  assert(lst >= begin);
4805  assert(flexenergies[idx] >= 0);
4806  flexenergy += flexenergies[idx];
4807  }
4808  else
4809  {
4810  /* the job partly overlaps with the end */
4811  int candenergy;
4812  int energy;
4813 
4814  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4815  * w.r.t. latest start time
4816  *
4817  * @note we need to be aware of the effective horizon
4818  */
4819  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4820  assert(end - lst < duration);
4821  assert(energy >= 0);
4822 
4823  /* adjust the flexible energy of the time interval */
4824  flexenergy += energy;
4825 
4826  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4827  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4828  assert(candenergy >= 0);
4829 
4830  /* check if we found a better candidate */
4831  if( candenergy > lbenergy )
4832  {
4833  lbenergy = candenergy;
4834  lbcand = idx;
4835  }
4836  }
4837 
4838  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4839  assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4840 
4841  /* compute the energy which is not used yet */
4842  freeenergy = capacity * (end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4843 
4844  /* check overload */
4845  if( freeenergy < 0 )
4846  {
4847  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4848 
4849  /* initialize conflict analysis if conflict analysis is applicable */
4851  {
4852  /* analyze infeasibilty */
4854 
4855  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4856  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
4857  conshdlrdata->usebdwidening, explanation) );
4858 
4859  (*initialized) = TRUE;
4860  }
4861 
4862  (*cutoff) = TRUE;
4863 
4864  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4865  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
4866 
4867  break;
4868  }
4869 
4870  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4871  if( lbenergy > 0 && freeenergy < lbenergy )
4872  {
4873  int energy;
4874  int newlb;
4875  int ect;
4876 
4877  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4878  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4879 
4880  /* remove the energy of our job from the ... */
4881  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, end - lsts[lbcand])) * demands[lbcand];
4882 
4883  newlb = end - (int)(energy / demands[lbcand]);
4884 
4885  if( newlb > lst )
4886  {
4887  /* initialize conflict analysis if conflict analysis is applicable */
4889  {
4890  SCIP_Real relaxedbd;
4891 
4892  /* analyze infeasibilty */
4894 
4895  relaxedbd = lst + 1.0;
4896 
4897  /* added to upper bound (which was overcut be new lower bound) of the variable */
4898  SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4899 
4900  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4901  begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
4902  conshdlrdata->usebdwidening, explanation) );
4903 
4904  (*initialized) = TRUE;
4905  }
4906 
4907  (*cutoff) = TRUE;
4908  break;
4909  }
4910  else if( newlb > newlbs[lbcand] )
4911  {
4912  INFERINFO inferinfo;
4913 
4914  /* construct inference information */
4915  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4916 
4917  /* buffer upper bound change */
4918  lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
4919  newlbs[lbcand] = newlb;
4920  }
4921  }
4922 
4923  /* check if the current interval has a smaller free energy */
4924  if( minavailable > freeenergy )
4925  {
4926  minavailable = freeenergy;
4927  minbegin = begin;
4928  }
4929  assert(minavailable >= 0);
4930  }
4931  }
4932 
4933  return SCIP_OKAY;
4934 }
4935 
4936 /** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
4937 static
4939  SCIP* scip, /**< SCIP data structure */
4940  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4941  int nvars, /**< number of start time variables (activities) */
4942  SCIP_VAR** vars, /**< array of start time variables */
4943  int* durations, /**< array of durations */
4944  int* demands, /**< array of demands */
4945  int capacity, /**< cumulative capacity */
4946  int hmin, /**< left bound of time axis to be considered (including hmin) */
4947  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4948  int* newlbs, /**< array to buffer new lower bounds */
4949  int* newubs, /**< array to buffer new upper bounds */
4950  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4951  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4952  int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
4953  int* flexenergies, /**< array of flexible energies in the same order as the variables */
4954  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
4955  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4956  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4957  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4958  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4959  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4960  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4961  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4962  )
4963 {
4964  int coreEnergyAfterStart;
4965  int maxavailable;
4966  int minavailable;
4967  int totalenergy;
4968  int nlcts;
4969  int begin;
4970  int minest;
4971  int maxlct;
4972  int start;
4973  int end;
4974  int v;
4975 
4976  if( *cutoff )
4977  return SCIP_OKAY;
4978 
4979  begin = hmin - 1;
4980 
4981  minest = INT_MAX;
4982  maxlct = INT_MIN;
4983 
4984  /* compute earliest start and latest completion time of all jobs */
4985  for( v = 0; v < nvars; ++v )
4986  {
4987  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4988  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4989 
4990  minest = MIN(minest, start);
4991  maxlct = MAX(maxlct, end);
4992  }
4993 
4994  /* adjust the effective time horizon */
4995  hmin = MAX(hmin, minest);
4996  hmax = MIN(hmax, maxlct);
4997 
4998  maxavailable = (hmax - hmin) * capacity;
4999  totalenergy = computeTotalEnergy(durations, demands, nvars);
5000 
5001  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5002  if( (lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5003  return SCIP_OKAY;
5004 
5005  nlcts = 0;
5006 
5007  /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5008  * define the start of the time interval under investigation
5009  */
5010  for( v = 0; v < nvars; ++v )
5011  {
5012  int flexenergy;
5013  int minend;
5014  int ubenergy;
5015  int ubcand;
5016  int est;
5017  int i;
5018 
5019  est = ests[v];
5020 
5021  /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5022  * infinity capacity is available; hence we skip that
5023  */
5024  if( est < hmin )
5025  continue;
5026 
5027  /* if the earliest start time is larger or equal then hmax we have to stop */
5028  if( est >= hmax )
5029  break;
5030 
5031  /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5032  * induced by start was just analyzed
5033  */
5034  if( est == begin )
5035  continue;
5036 
5037  assert(est > begin);
5038 
5039  SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5040 
5041  begin = est;
5042  coreEnergyAfterStart = coreEnergyAfterEst[v];
5043 
5044  flexenergy = 0;
5045  minavailable = maxavailable;
5046  minend = hmin;
5047  ubcand = -1;
5048  ubenergy = 0;
5049 
5050  /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5051  * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5052  */
5053  for( i = nlcts; i < nvars; ++i )
5054  {
5055  SCIP_VAR* var;
5056  int freeenergy;
5057  int duration;
5058  int demand;
5059  int idx;
5060  int lct;
5061  int ect;
5062 
5063  idx = perm[i];
5064  assert(idx >= 0);
5065  assert(idx < nvars);
5066  assert(!(*cutoff));
5067 
5068  /* the earliest start time of the job */
5069  lct = lcts[i];
5070 
5071  /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5072  * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5073  */
5074  if( lct <= begin )
5075  {
5076  nlcts++;
5077  continue;
5078  }
5079 
5080  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5081  * start with current beginning time
5082  */
5083  if( (lct - begin) * capacity >= totalenergy )
5084  break;
5085 
5086  var = vars[idx];
5087  assert(var != NULL);
5088 
5089  duration = durations[idx];
5090  assert(duration > 0);
5091 
5092  demand = demands[idx];
5093  assert(demand > 0);
5094 
5095  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5096 
5097  /* the earliest completion time of the flexible part of the job */
5098  ect = ects[idx];
5099 
5100  /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5101  * investigation; hence the overload check will do the the job
5102  */
5103  assert(lct >= minend);
5104  if( minavailable < maxavailable && lct > minend )
5105  {
5106  assert(!(*cutoff));
5107 
5108  /* try to tighten the upper bound */
5109  SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5110  var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5111  initialized, explanation, cutoff) );
5112 
5113  if( *cutoff )
5114  return SCIP_OKAY;
5115  }
5116 
5117  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5118  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5119 
5120  end = lct;
5121  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5122 
5123  /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5124  * free energy
5125  */
5126  if( end > hmax )
5127  break;
5128 
5129  /* compute the contribution to the flexible energy */
5130  if( est >= begin )
5131  {
5132  /* if the jobs has to finish before the end, all the energy has to be scheduled */
5133  assert(ect <= end);
5134  assert(flexenergies[idx] >= 0);
5135  flexenergy += flexenergies[idx];
5136  }
5137  else
5138  {
5139  /* the job partly overlaps with the end */
5140  int candenergy;
5141  int energy;
5142 
5143  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5144  * w.r.t. latest start time
5145  *
5146  * @note we need to be aware of the effective horizon
5147  */
5148  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5149  assert(ect - begin < duration);
5150  assert(energy >= 0);
5151 
5152  /* adjust the flexible energy of the time interval */
5153  flexenergy += energy;
5154 
5155  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5156  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5157  assert(candenergy >= 0);
5158 
5159  /* check if we found a better candidate */
5160  if( candenergy > ubenergy )
5161  {
5162  ubenergy = candenergy;
5163  ubcand = idx;
5164  }
5165  }
5166 
5167  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5168  assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5169 
5170  /* compute the energy which is not used yet */
5171  freeenergy = capacity * (end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5172 
5173  /* check overload */
5174  if( freeenergy < 0 )
5175  {
5176  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5177 
5178  /* initialize conflict analysis if conflict analysis is applicable */
5180  {
5181  /* analyze infeasibilty */
5183 
5184  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5185  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
5186  conshdlrdata->usebdwidening, explanation) );
5187 
5188  (*initialized) = TRUE;
5189  }
5190 
5191  (*cutoff) = TRUE;
5192 
5193  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5194  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5195 
5196  return SCIP_OKAY;
5197  }
5198 
5199  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5200  if( ubenergy > 0 && freeenergy < ubenergy )
5201  {
5202  int energy;
5203  int newub;
5204  int lst;
5205 
5206  duration = durations[ubcand];
5207  assert(duration > 0);
5208 
5209  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5210  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5211 
5212  /* remove the energy of our job from the ... */
5213  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, ects[ubcand] - begin)) * demands[ubcand];
5214 
5215  newub = begin - duration + (int)(energy / demands[ubcand]);
5216 
5217  if( newub < ect - duration )
5218  {
5219  /* initialize conflict analysis if conflict analysis is applicable */
5221  {
5222  SCIP_Real relaxedbd;
5223  /* analyze infeasibilty */
5225 
5226  relaxedbd = ect - duration - 1.0;
5227 
5228  /* added to lower bound (which was undercut be new upper bound) of the variable */
5229  SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5230 
5231  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5232  begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5233  conshdlrdata->usebdwidening, explanation) );
5234 
5235  (*initialized) = TRUE;
5236  }
5237 
5238  (*cutoff) = TRUE;
5239  return SCIP_OKAY;
5240  }
5241  else if( newub < newubs[ubcand] )
5242  {
5243  INFERINFO inferinfo;
5244 
5245  /* construct inference information */
5246  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5247 
5248  /* buffer upper bound change */
5249  ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5250  newubs[ubcand] = newub;
5251  }
5252  }
5253 
5254  /* check if the current interval has a smaller free energy */
5255  if( minavailable > freeenergy )
5256  {
5257  minavailable = freeenergy;
5258  minend = end;
5259  }
5260  assert(minavailable >= 0);
5261  }
5262  }
5263 
5264  return SCIP_OKAY;
5265 }
5266 
5267 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5268  * edge-finding
5269  *
5270  * @note The algorithm is based on the following two papers:
5271  * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5272  * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5273  * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5274  * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5275  * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5276  */
5277 static
5279  SCIP* scip, /**< SCIP data structure */
5280  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5281  SCIP_PROFILE* profile, /**< current core profile */
5282  int nvars, /**< number of start time variables (activities) */
5283  SCIP_VAR** vars, /**< array of start time variables */
5284  int* durations, /**< array of durations */
5285  int* demands, /**< array of demands */
5286  int capacity, /**< cumulative capacity */
5287  int hmin, /**< left bound of time axis to be considered (including hmin) */
5288  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5289  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5290  int* nchgbds, /**< pointer to store the number of bound changes */
5291  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5292  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5293  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5294  )
5295 {
5296  int* coreEnergyAfterEst;
5297  int* coreEnergyAfterLct;
5298  int* flexenergies;
5299  int* permests;
5300  int* permlcts;
5301  int* lcts;
5302  int* ests;
5303  int* ects;
5304  int* lsts;
5305 
5306  int* newlbs;
5307  int* newubs;
5308  int* lbinferinfos;
5309  int* ubinferinfos;
5310 
5311  int v;
5312 
5313  /* check if a cutoff was already detected */
5314  if( (*cutoff) )
5315  return SCIP_OKAY;
5316 
5317  /* check if at least the basic overload checking should be perfomed */
5318  if( !conshdlrdata->ttefcheck )
5319  return SCIP_OKAY;
5320 
5321  SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5322 
5323  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5324  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5325  SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5326  SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5327  SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5328  SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5329  SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5330  SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5331  SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5332 
5333  SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5334  SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5335  SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5336  SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5337 
5338  /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5339  for( v = 0; v < nvars; ++v )
5340  {
5341  newlbs[v] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5342  newubs[v] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5343  lbinferinfos[v] = 0;
5344  ubinferinfos[v] = 0;
5345  }
5346 
5347  /* collect earliest start times, latest completion time, and free energy contributions */
5348  collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5349 
5350  /* sort the earliest start times and latest completion in non-decreasing order */
5351  SCIPsortIntInt(ests, permests, nvars);
5352  SCIPsortIntInt(lcts, permlcts, nvars);
5353 
5354  /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5355  * points
5356  */
5357  SCIP_CALL( computeCoreEngeryAfter(scip, profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct) );
5358 
5359  /* propagate the upper bounds and "opportunistically" the lower bounds */
5360  SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5361  newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5362  permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5363 
5364  /* propagate the lower bounds and "opportunistically" the upper bounds */
5365  SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5366  newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5367  permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5368 
5369  /* apply the buffer bound changes */
5370  for( v = 0; v < nvars && !(*cutoff); ++v )
5371  {
5372  SCIP_Bool infeasible;
5373  SCIP_Bool tightened;
5374 
5375  SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v], TRUE, &infeasible, &tightened) );
5376 
5377  /* since we change first the lower bound of the variable an infeasibilty should be detected */
5378  assert(!infeasible);
5379 
5380  if( tightened )
5381  {
5382  (*nchgbds)++;
5383 
5384  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5386  }
5387 
5388 
5389  SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v], TRUE, &infeasible, &tightened) );
5390 
5391  /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5392  * bound update can be infeasible
5393  */
5394  if( infeasible )
5395  {
5397  {
5398  INFERINFO inferinfo;
5399  SCIP_VAR* var;
5400  int begin;
5401  int end;
5402 
5403  var = vars[v];
5404  assert(var != NULL);
5405 
5406  /* initialize conflict analysis */
5408 
5409  /* convert int to inference information */
5410  inferinfo = intToInferInfo(ubinferinfos[v]);
5411 
5412  /* collect time window from inference information */
5413  begin = inferInfoGetData1(inferinfo);
5414  end = inferInfoGetData2(inferinfo);
5415  assert(begin < end);
5416 
5417  /* added to lower bound (which was undercut be new upper bound) of the variable */
5418  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
5419 
5420  /* analysis the upper bound change */
5421  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5422  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5423  conshdlrdata->usebdwidening, explanation) );
5424 
5425  (*initialized) = TRUE;
5426  }
5427 
5428  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5429  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5430 
5431  (*cutoff) = TRUE;
5432  break;
5433  }
5434 
5435  if( tightened )
5436  {
5437  (*nchgbds)++;
5438 
5439  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5441  }
5442  }
5443 
5444  SCIPfreeBufferArray(scip, &ubinferinfos);
5445  SCIPfreeBufferArray(scip, &lbinferinfos);
5446  SCIPfreeBufferArray(scip, &newubs);
5447  SCIPfreeBufferArray(scip, &newlbs);
5448 
5449  /* free buffer arrays */
5450  SCIPfreeBufferArray(scip, &lsts);
5451  SCIPfreeBufferArray(scip, &ects);
5452  SCIPfreeBufferArray(scip, &ests);
5453  SCIPfreeBufferArray(scip, &lcts);
5454  SCIPfreeBufferArray(scip, &permests);
5455  SCIPfreeBufferArray(scip, &permlcts);
5456  SCIPfreeBufferArray(scip, &flexenergies);
5457  SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5458  SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5459 
5460  return SCIP_OKAY;
5461 }
5462 
5463 /** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5464  * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5465  * time table propagator
5466  */
5467 static
5469  SCIP* scip, /**< SCIP data structure */
5470  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5471  SCIP_PROFILE* profile, /**< core profile */
5472  int nvars, /**< number of start time variables (activities) */
5473  SCIP_VAR** vars, /**< array of start time variables */
5474  int* durations, /**< array of durations */
5475  int* demands, /**< array of demands */
5476  int capacity, /**< cumulative capacity */
5477  int hmin, /**< left bound of time axis to be considered (including hmin) */
5478  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5479  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5480  int* nchgbds, /**< pointer to store the number of bound changes */
5481  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5482  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5483  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5484  )
5485 {
5486  SCIP_Bool infeasible;
5487  int v;
5488 
5489  assert(scip != NULL);
5490  assert(nvars > 0);
5491  assert(cons != NULL);
5492  assert(cutoff != NULL);
5493 
5494  /* check if already a cutoff was detected */
5495  if( (*cutoff) )
5496  return SCIP_OKAY;
5497 
5498  /* check if the time tabling should infer bounds */
5499  if( !conshdlrdata->ttinfer )
5500  return SCIP_OKAY;
5501 
5502  assert(*initialized == FALSE);
5503 
5504  SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5505  SCIPconsGetName(cons), hmin, hmax, capacity);
5506 
5507  infeasible = FALSE;
5508 
5509  /* if core profile is empty; nothing to do */
5510  if( SCIPprofileGetNTimepoints(profile) <= 1 )
5511  return SCIP_OKAY;
5512 
5513  /* start checking each job whether the bounds can be improved */
5514  for( v = 0; v < nvars; ++v )
5515  {
5516  SCIP_VAR* var;
5517  int demand;
5518  int duration;
5519  int begin;
5520  int end;
5521  int est;
5522  int lst;
5523 
5524  var = vars[v];
5525  assert(var != NULL);
5526 
5527  duration = durations[v];
5528  assert(duration > 0);
5529 
5530  /* collect earliest and latest start time */
5531  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5532  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5533 
5534  /* check if the start time variables is already fixed; in that case we can ignore the job */
5535  if( est == lst )
5536  continue;
5537 
5538  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5539  if( lst + duration <= hmin || est >= hmax )
5540  continue;
5541 
5542  /* compute core interval w.r.t. effective time horizon */
5543  begin = MAX(hmin, lst);
5544  end = MIN(hmax, est + duration);
5545 
5546  demand = demands[v];
5547  assert(demand > 0);
5548 
5549  /* if the job has a core, remove it first */
5550  if( begin < end )
5551  {
5552  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5553  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5554 
5555  SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5556  }
5557 
5558  /* first try to update the earliest start time */
5559  SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5560  profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5561 
5562  if( *cutoff )
5563  break;
5564 
5565  /* second try to update the latest start time */
5566  SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5567  profile, v, nchgbds) );
5568 
5569  if( *cutoff )
5570  break;
5571 
5572  /* collect the potentially updated earliest and latest start time */
5573  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5574  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5575 
5576  /* compute core interval w.r.t. effective time horizon */
5577  begin = MAX(hmin, lst);
5578  end = MIN(hmax, est + duration);
5579 
5580  /* after updating the bound we might have a new core */
5581  if( begin < end )
5582  {
5583  int pos;
5584 
5585  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5586  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5587 
5588  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5589 
5590  if( infeasible )
5591  {
5592  /* use conflict analysis to analysis the core insertion which was infeasible */
5593  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5594  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5595 
5596  if( explanation != NULL )
5597  explanation[v] = TRUE;
5598 
5599  (*cutoff) = TRUE;
5600 
5601  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5602  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
5603 
5604  break;
5605  }
5606  }
5607  }
5608 
5609  return SCIP_OKAY;
5610 }
5611 
5612 
5613 /** node data structure for the binary tree used for edgefinding (with overload checking) */
5614 struct SCIP_NodeData
5615 {
5616  SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5617  SCIP_Real key; /**< key which is to insert the corresponding search node */
5618  int est; /**< earliest start time if the node data belongs to a leaf */
5619  int lct; /**< latest completion time if the node data belongs to a leaf */
5620  int demand; /**< demand of the job if the node data belongs to a leaf */
5621  int duration; /**< duration of the job if the node data belongs to a leaf */
5622  int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5623  int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5624  int enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5625  int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5626  int energylambda;
5627  int enveloplambda;
5628  int idx; /**< index of the start time variable in the (global) variable array */
5629  SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5630 };
5631 typedef struct SCIP_NodeData SCIP_NODEDATA;
5633 /** creates a node data structure */
5634 static
5636  SCIP* scip, /**< SCIP data structure */
5637  SCIP_NODEDATA** nodedata /**< pointer to store the create node data */
5638  )
5639 {
5640  SCIP_CALL( SCIPallocBuffer(scip, nodedata) );
5641  (*nodedata)->var = NULL;
5642  (*nodedata)->key = SCIP_INVALID;
5643  (*nodedata)->est = INT_MIN;
5644  (*nodedata)->lct = INT_MAX;
5645  (*nodedata)->duration = 0;
5646  (*nodedata)->demand = 0;
5647  (*nodedata)->enveloptheta = -1;
5648  (*nodedata)->energytheta = 0;
5649  (*nodedata)->enveloplambda = -1;
5650  (*nodedata)->energylambda = -1;
5651  (*nodedata)->idx = -1;
5652  (*nodedata)->intheta = TRUE;
5653 
5654  return SCIP_OKAY;
5655 }
5656 
5657 /** frees a node data structure */
5658 static
5659 void freeNodedata(
5660  SCIP* scip, /**< SCIP data structure */
5661  SCIP_NODEDATA** nodedata /**< pointer to store node data which should be freed */
5662  )
5663 {
5664  if( *nodedata != NULL )
5665  {
5666  SCIPfreeBuffer(scip, nodedata);
5667  }
5668 }
5669 
5670 /** update node data structure strating form the given node along the path to the root node */
5671 static
5673  SCIP* scip, /**< SCIP data structure */
5674  SCIP_BTNODE* node /**< search node which inserted */
5675  )
5676 {
5677  SCIP_BTNODE* left;
5678  SCIP_BTNODE* right;
5679  SCIP_NODEDATA* nodedata;
5680  SCIP_NODEDATA* leftdata;
5681  SCIP_NODEDATA* rightdata;
5682 
5683  SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5684 
5685  if( SCIPbtnodeIsLeaf(node) )
5686  node = SCIPbtnodeGetParent(node);
5687 
5688  while( node != NULL )
5689  {
5690  /* get node data */
5691  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5692  assert(nodedata != NULL);
5693 
5694  /* collect node data from left node */
5695  left = SCIPbtnodeGetLeftchild(node);
5696  assert(left != NULL);
5697  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5698  assert(leftdata != NULL);
5699 
5700  /* collect node data from right node */
5701  right = SCIPbtnodeGetRightchild(node);
5702  assert(right != NULL);
5703  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5704  assert(rightdata != NULL);
5705 
5706  /* update envelop and energy */
5707  if( leftdata->enveloptheta >= 0 )
5708  {
5709  assert(rightdata->energytheta != -1);
5710  nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5711  }
5712  else
5713  nodedata->enveloptheta = rightdata->enveloptheta;
5714 
5715  assert(leftdata->energytheta != -1);
5716  assert(rightdata->energytheta != -1);
5717  nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5718 
5719  if( leftdata->enveloplambda >= 0 )
5720  {
5721  assert(rightdata->energytheta != -1);
5722  nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5723  }
5724  else
5725  nodedata->enveloplambda = rightdata->enveloplambda;
5726 
5727  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5728  nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5729 
5730  SCIPdebugMsg(scip, "node <%p> lambda envelop %d\n", (void*)node, nodedata->enveloplambda);
5731 
5732  if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5733  {
5734  assert(rightdata->energytheta != -1);
5735  assert(leftdata->energytheta != -1);
5736  nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5737  }
5738  else if( rightdata->energylambda >= 0 )
5739  {
5740  assert(leftdata->energytheta != -1);
5741  nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5742  }
5743  else if( leftdata->energylambda >= 0 )
5744  {
5745  assert(rightdata->energytheta != -1);
5746  nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5747  }
5748  else
5749  nodedata->energylambda = -1;
5750 
5751  /* go to parent */
5752  node = SCIPbtnodeGetParent(node);
5753  }
5754 
5755  SCIPdebugMsg(scip, "updating done\n");
5756 
5757  return SCIP_OKAY;
5758 }
5759 
5760 /** updates the key of the first parent on the trace which comes from left */
5761 static
5762 void updateKeyOnTrace(
5763  SCIP_BTNODE* node, /**< node to start the trace */
5764  SCIP_Real key /**< update search key */
5765  )
5766 {
5767  assert(node != NULL);
5768 
5769  while( !SCIPbtnodeIsRoot(node) )
5770  {
5771  SCIP_BTNODE* parent;
5772 
5773  parent = SCIPbtnodeGetParent(node);
5774  assert(parent != NULL);
5775 
5776  if( SCIPbtnodeIsLeftchild(node) )
5777  {
5778  SCIP_NODEDATA* nodedata;
5779 
5780  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(parent);
5781  assert(nodedata != NULL);
5782 
5783  nodedata->key = key;
5784  return;
5785  }
5786 
5787  node = parent;
5788  }
5789 }
5790 
5791 
5792 /** deletes the given node and updates all envelops */
5793 static
5795  SCIP* scip, /**< SCIP data structure */
5796  SCIP_BT* tree, /**< binary tree */
5797  SCIP_BTNODE* node /**< node to be deleted */
5798  )
5799 {
5800  SCIP_BTNODE* parent;
5801  SCIP_BTNODE* grandparent;
5802  SCIP_BTNODE* sibling;
5803 
5804  assert(scip != NULL);
5805  assert(tree != NULL);
5806  assert(node != NULL);
5807 
5808  assert(SCIPbtnodeIsLeaf(node));
5809  assert(!SCIPbtnodeIsRoot(node));
5810 
5811  SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5812 
5813  parent = SCIPbtnodeGetParent(node);
5814  assert(parent != NULL);
5815  if( SCIPbtnodeIsLeftchild(node) )
5816  {
5817  sibling = SCIPbtnodeGetRightchild(parent);
5818  SCIPbtnodeSetRightchild(parent, NULL);
5819  }
5820  else
5821  {
5822  sibling = SCIPbtnodeGetLeftchild(parent);
5823  SCIPbtnodeSetLeftchild(parent, NULL);
5824  }
5825  assert(sibling != NULL);
5826 
5827  grandparent = SCIPbtnodeGetParent(parent);
5828 
5829  if( grandparent != NULL )
5830  {
5831  /* reset parent of sibling */
5832  SCIPbtnodeSetParent(sibling, grandparent);
5833 
5834  /* reset child of grandparent to sibling */
5835  if( SCIPbtnodeIsLeftchild(parent) )
5836  {
5837  SCIPbtnodeSetLeftchild(grandparent, sibling);
5838  }
5839  else
5840  {
5841  SCIP_NODEDATA* nodedata;
5842 
5843  assert(SCIPbtnodeIsRightchild(parent));
5844  SCIPbtnodeSetRightchild(grandparent, sibling);
5845 
5846  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(sibling);
5847 
5848  updateKeyOnTrace(grandparent, nodedata->key);
5849  }
5850 
5851  SCIP_CALL( updateEnvelop(scip, grandparent) );
5852  }
5853  else
5854  {
5855  SCIPbtnodeSetParent(sibling, NULL);
5856 
5857  SCIPbtSetRoot(tree, sibling);
5858  }
5859 
5860 
5861  SCIPbtnodeFree(tree, &parent);
5862 
5863  return SCIP_OKAY;
5864 }
5865 
5866 /** moves a node form the theta set into the lambda set and updates the envelops */
5867 static
5869  SCIP* scip, /**< SCIP data structure */
5870  SCIP_BT* tree, /**< binary tree */
5871  SCIP_BTNODE* node /**< node to move into the lambda set */
5872  )
5873 {
5874  SCIP_NODEDATA* nodedata;
5875 
5876  assert(scip != NULL);
5877  assert(tree != NULL);
5878  assert(node != NULL);
5879 
5880  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5881  assert(nodedata != NULL);
5882  assert(nodedata->intheta);
5883 
5884  /* move the contributions form the theta set into the lambda set */
5885  assert(nodedata->enveloptheta != -1);
5886  assert(nodedata->energytheta != -1);
5887  assert(nodedata->enveloplambda == -1);
5888  assert(nodedata->energylambda == -1);
5889  nodedata->enveloplambda = nodedata->enveloptheta;
5890  nodedata->energylambda = nodedata->energytheta;
5891 
5892  nodedata->enveloptheta = -1;
5893  nodedata->energytheta = 0;
5894  nodedata->intheta = FALSE;
5895 
5896  /* update the energy and envelop values on trace */
5897  SCIP_CALL( updateEnvelop(scip, node) );
5898 
5899  return SCIP_OKAY;
5900 }
5901 
5902 /** inserts a node into the theta set and update the envelops */
5903 static
5905  SCIP* scip, /**< SCIP data structure */
5906  SCIP_BT* tree, /**< binary tree */
5907  SCIP_BTNODE* node, /**< node to insert */
5908  SCIP_NODEDATA** nodedatas, /**< array of node data */
5909  int* nnodedatas /**< pointer to number of node data */
5910  )
5911 {
5912  /* if the tree is empty the node will be the root node */
5913  if( SCIPbtIsEmpty(tree) )
5914  {
5915  SCIPbtSetRoot(tree, node);
5916  }
5917  else
5918  {
5919  SCIP_NODEDATA* newnodedata;
5920  SCIP_NODEDATA* leafdata;
5921  SCIP_NODEDATA* nodedata;
5922  SCIP_BTNODE* leaf;
5923  SCIP_BTNODE* newnode;
5924  SCIP_BTNODE* parent;
5925 
5926  leaf = SCIPbtGetRoot(tree);
5927  assert(leaf != NULL);
5928 
5929  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5930  assert(leafdata != NULL);
5931 
5932  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5933  assert(nodedata != NULL);
5934  assert(nodedata->intheta);
5935 
5936  /* find the position to insert the node */
5937  while( !SCIPbtnodeIsLeaf(leaf) )
5938  {
5939  if( nodedata->key < leafdata->key )
5940  leaf = SCIPbtnodeGetLeftchild(leaf);
5941  else
5942  leaf = SCIPbtnodeGetRightchild(leaf);
5943 
5944  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5945  assert(leafdata != NULL);
5946  }
5947 
5948  assert(leaf != NULL);
5949  assert(leaf != node);
5950 
5951  /* create node data */
5952  SCIP_CALL( createNodedata(scip, &newnodedata) );
5953 
5954  /* create a new node */
5955  SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
5956  assert(newnode != NULL);
5957 
5958  /* store node data to be able to delete them latter */
5959  nodedatas[*nnodedatas] = newnodedata;
5960  (*nnodedatas)++;
5961 
5962  parent = SCIPbtnodeGetParent(leaf);
5963 
5964  if( parent != NULL )
5965  {
5966  SCIPbtnodeSetParent(newnode, parent);
5967 
5968  /* check if the node is the left child */
5969  if( SCIPbtnodeGetLeftchild(parent) == leaf )
5970  {
5971  SCIPbtnodeSetLeftchild(parent, newnode);
5972  }
5973  else
5974  {
5975  SCIPbtnodeSetRightchild(parent, newnode);
5976  }
5977  }
5978  else
5979  SCIPbtSetRoot(tree, newnode);
5980 
5981  if( nodedata->key < leafdata->key )
5982  {
5983  /* node is on the left */
5984  SCIPbtnodeSetLeftchild(newnode, node);
5985  SCIPbtnodeSetRightchild(newnode, leaf);
5986  newnodedata->key = nodedata->key;
5987  }
5988  else
5989  {
5990  /* leaf is on the left */
5991  SCIPbtnodeSetLeftchild(newnode, leaf);
5992  SCIPbtnodeSetRightchild(newnode, node);
5993  newnodedata->key = leafdata->key;
5994  }
5995 
5996  SCIPbtnodeSetParent(leaf, newnode);
5997  SCIPbtnodeSetParent(node, newnode);
5998  }
5999 
6000  /* update envelop */
6001  SCIP_CALL( updateEnvelop(scip, node) );
6002 
6003  return SCIP_OKAY;
6004 }
6005 
6006 /** returns the leaf responsible for the lambda energy */
6007 static
6009  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6010  )
6011 {
6012  SCIP_BTNODE* left;
6013  SCIP_BTNODE* right;
6014  SCIP_NODEDATA* nodedata;
6015  SCIP_NODEDATA* leftdata;
6016  SCIP_NODEDATA* rightdata;
6017 
6018  assert(node != NULL);
6019 
6020  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6021  assert(nodedata != NULL);
6022 
6023  /* check if the node is the (responsible) leaf */
6024  if( SCIPbtnodeIsLeaf(node) )
6025  {
6026  assert(!nodedata->intheta);
6027  return node;
6028  }
6029 
6030  left = SCIPbtnodeGetLeftchild(node);
6031  assert(left != NULL);
6032 
6033  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6034  assert(leftdata != NULL);
6035 
6036  right = SCIPbtnodeGetRightchild(node);
6037  assert(right != NULL);
6038 
6039  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6040  assert(rightdata != NULL);
6041 
6042  assert(nodedata->energylambda != -1);
6043  assert(rightdata->energytheta != -1);
6044 
6045  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6047 
6048  assert(leftdata->energytheta != -1);
6049  assert(rightdata->energylambda != -1);
6050  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6051 
6053 }
6054 
6055 /** returns the leaf responsible for the lambda envelop */
6056 static
6058  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6059  )
6060 {
6061  SCIP_BTNODE* left;
6062  SCIP_BTNODE* right;
6063  SCIP_NODEDATA* nodedata;
6064  SCIP_NODEDATA* leftdata;
6065  SCIP_NODEDATA* rightdata;
6066 
6067  assert(node != NULL);
6068 
6069  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6070  assert(nodedata != NULL);
6071 
6072  /* check if the node is the (responsible) leaf */
6073  if( SCIPbtnodeIsLeaf(node) )
6074  {
6075  assert(!nodedata->intheta);
6076  return node;
6077  }
6078 
6079  left = SCIPbtnodeGetLeftchild(node);
6080  assert(left != NULL);
6081 
6082  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6083  assert(leftdata != NULL);
6084 
6085  right = SCIPbtnodeGetRightchild(node);
6086  assert(right != NULL);
6087 
6088  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6089  assert(rightdata != NULL);
6090 
6091  assert(nodedata->enveloplambda != -1);
6092  assert(rightdata->energytheta != -1);
6093 
6094  /* check if the left or right child is the one defining the envelop for the lambda set */
6095  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6097  else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6098  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6100 
6101  assert(rightdata->enveloplambda != -1);
6102  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6103 
6105 }
6106 
6107 
6108 /** reports all elements from set theta to generate a conflicting set */
6109 static
6110 void collectThetaSubtree(
6111  SCIP_BTNODE* node, /**< node within a theta subtree */
6112  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6113  int* nelements, /**< pointer to store the number of elements in omegaset */
6114  int* est, /**< pointer to store the earliest start time of the omega set */
6115  int* lct, /**< pointer to store the latest start time of the omega set */
6116  int* energy /**< pointer to store the energy of the omega set */
6117  )
6118 {
6119  SCIP_NODEDATA* nodedata;
6120 
6121  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6122  assert(nodedata != NULL);
6123 
6124  if( !SCIPbtnodeIsLeaf(node) )
6125  {
6126  collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6127  collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6128  }
6129  else if( nodedata->intheta )
6130  {
6131  assert(nodedata->var != NULL);
6132  SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6133 
6134  omegaset[*nelements] = node;
6135  (*est) = MIN(*est, nodedata->est);
6136  (*lct) = MAX(*lct, nodedata->lct);
6137  (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6138  (*nelements)++;
6139  }
6140 }
6141 
6142 
6143 /** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6144 static
6145 void traceThetaEnvelop(
6146  SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6147  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6148  int* nelements, /**< pointer to store the number of elements in omegaset */
6149  int* est, /**< pointer to store the earliest start time of the omega set */
6150  int* lct, /**< pointer to store the latest start time of the omega set */
6151  int* energy /**< pointer to store the energy of the omega set */
6152  )
6153 {
6154  assert(node != NULL);
6155 
6156  if( SCIPbtnodeIsLeaf(node) )
6157  {
6158  collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6159  }
6160  else
6161  {
6162  SCIP_BTNODE* left;
6163  SCIP_BTNODE* right;
6164  SCIP_NODEDATA* nodedata;
6165  SCIP_NODEDATA* leftdata;
6166  SCIP_NODEDATA* rightdata;
6167 
6168  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6169  assert(nodedata != NULL);
6170 
6171 
6172  left = SCIPbtnodeGetLeftchild(node);
6173  assert(left != NULL);
6174 
6175  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6176  assert(leftdata != NULL);
6177 
6178  right = SCIPbtnodeGetRightchild(node);
6179  assert(right != NULL);
6180 
6181  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6182  assert(rightdata != NULL);
6183 
6184  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6185  assert(nodedata != NULL);
6186 
6187  assert(nodedata->enveloptheta != -1);
6188  assert(rightdata->energytheta != -1);
6189 
6190  if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6191  {
6192  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6193  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6194  }
6195  else
6196  {
6197  assert(rightdata->enveloptheta != -1);
6198  assert(nodedata->enveloptheta == rightdata->enveloptheta);
6199  traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6200  }
6201  }
6202 }
6203 
6204 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6205 static
6206 void traceLambdaEnergy(
6207  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6208  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6209  int* nelements, /**< pointer to store the number of elements in omega set */
6210  int* est, /**< pointer to store the earliest start time of the omega set */
6211  int* lct, /**< pointer to store the latest start time of the omega set */
6212  int* energy /**< pointer to store the energy of the omega set */
6213  )
6214 {
6215  SCIP_BTNODE* left;
6216  SCIP_BTNODE* right;
6217  SCIP_NODEDATA* nodedata;
6218  SCIP_NODEDATA* leftdata;
6219  SCIP_NODEDATA* rightdata;
6220 
6221  assert(node != NULL);
6222 
6223  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6224  assert(nodedata != NULL);
6225 
6226  /* check if the node is a leaf */
6227  if( SCIPbtnodeIsLeaf(node) )
6228  return;
6229 
6230  left = SCIPbtnodeGetLeftchild(node);
6231  assert(left != NULL);
6232 
6233  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6234  assert(leftdata != NULL);
6235 
6236  right = SCIPbtnodeGetRightchild(node);
6237  assert(right != NULL);
6238 
6239  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6240  assert(rightdata != NULL);
6241 
6242  assert(nodedata->energylambda != -1);
6243  assert(rightdata->energytheta != -1);
6244 
6245  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6246  {
6247  traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6248  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6249  }
6250  else
6251  {
6252  assert(leftdata->energytheta != -1);
6253  assert(rightdata->energylambda != -1);
6254  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6255 
6256  collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6257  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6258  }
6259 }
6260 
6261 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6262 static
6263 void traceLambdaEnvelop(
6264  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6265  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6266  int* nelements, /**< pointer to store the number of elements in omega set */
6267  int* est, /**< pointer to store the earliest start time of the omega set */
6268  int* lct, /**< pointer to store the latest start time of the omega set */
6269  int* energy /**< pointer to store the energy of the omega set */
6270  )
6271 {
6272  SCIP_BTNODE* left;
6273  SCIP_BTNODE* right;
6274  SCIP_NODEDATA* nodedata;
6275  SCIP_NODEDATA* leftdata;
6276  SCIP_NODEDATA* rightdata;
6277 
6278  assert(node != NULL);
6279 
6280  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6281  assert(nodedata != NULL);
6282 
6283  /* check if the node is a leaf */
6284  if( SCIPbtnodeIsLeaf(node) )
6285  {
6286  assert(!nodedata->intheta);
6287  return;
6288  }
6289 
6290  left = SCIPbtnodeGetLeftchild(node);
6291  assert(left != NULL);
6292 
6293  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6294  assert(leftdata != NULL);
6295 
6296  right = SCIPbtnodeGetRightchild(node);
6297  assert(right != NULL);
6298 
6299  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6300  assert(rightdata != NULL);
6301 
6302  assert(nodedata->enveloplambda != -1);
6303  assert(rightdata->energytheta != -1);
6304 
6305  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6306  {
6307  traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6308  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6309  }
6310  else
6311  {
6312  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6313  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6314  {
6315  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6316  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6317  }
6318  else
6319  {
6320  assert(rightdata->enveloplambda != -1);
6321  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6322  traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6323  }
6324  }
6325 }
6326 
6327 /** compute the energy contribution by job which corresponds to the given leaf */
6328 static
6330  SCIP_BTNODE* node /**< leaf */
6331  )
6332 {
6333  SCIP_NODEDATA* nodedata;
6334  int duration;
6335 
6336  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6337  assert(nodedata != NULL);
6338  assert(nodedata->var != NULL);
6339 
6340  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6341  assert(duration > 0);
6342 
6343  SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6345  SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6346 
6347  /* return energy which is contributed by the start time variable */
6348  return nodedata->demand * duration;
6349 }
6350 
6351 /** comparison method for two node data w.r.t. the earliest start time */
6352 static
6353 SCIP_DECL_SORTPTRCOMP(compNodeEst)
6355  int est1;
6356  int est2;
6357 
6358  est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6359  est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6360 
6361  return (est1 - est2);
6362 }
6363 
6364 /** comparison method for two node data w.r.t. the latest completion time */
6365 static
6366 SCIP_DECL_SORTPTRCOMP(compNodedataLct)
6368  int lct1;
6369  int lct2;
6370 
6371  lct1 = ((SCIP_NODEDATA*)elem1)->lct;
6372  lct2 = ((SCIP_NODEDATA*)elem2)->lct;
6373 
6374  return (lct1 - lct2);
6375 }
6376 
6377 
6378 /** an overload was detected; initialized conflict analysis, add an initial reason
6379  *
6380  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6381  */
6382 static
6384  SCIP* scip, /**< SCIP data structure */
6385  SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6386  int capacity, /**< cumulative capacity */
6387  int nleaves, /**< number of responsible leaves */
6388  int est, /**< earliest start time of the ...... */
6389  int lct, /**< latest completly time of the .... */
6390  int reportedenergy, /**< energy which already reported */
6391  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6392  int shift, /**< shift applied to all jobs before adding them to the tree */
6393  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6394  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6395  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6396  )
6397 {
6398  int energy;
6399  int j;
6400 
6401  /* do nothing if conflict analysis is not applicable */
6403  return SCIP_OKAY;
6404 
6405  SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6406 
6407  /* compute energy of initial time window */
6408  energy = (lct - est) * capacity;
6409 
6410  /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6411  SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6412 
6413  /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6414  * thereby, compute the time window of interest
6415  */
6416  for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6417  {
6418  SCIP_NODEDATA* nodedata;
6419 
6420  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6421  assert(nodedata != NULL);
6422 
6423  reportedenergy += computeEnergyContribution(leaves[j]);
6424 
6425  /* adjust energy if the earliest start time decrease */
6426  if( nodedata->est < est )
6427  {
6428  est = nodedata->est;
6429  energy = (lct - est) * capacity;
6430  }
6431  }
6432  assert(reportedenergy > energy);
6433 
6434  SCIPdebugMsg(scip, "time window [%d,%d) available energy %d, required energy %d\n", est, lct, energy, reportedenergy);
6435 
6436  /* initialize conflict analysis */
6438 
6439  /* flip earliest start time and latest completion time */
6440  if( !propest )
6441  {
6442  SCIPswapInts(&est, &lct);
6443 
6444  /* shift earliest start time and latest completion time */
6445  lct = shift - lct;
6446  est = shift - est;
6447  }
6448  else
6449  {
6450  /* shift earliest start time and latest completion time */
6451  lct = lct + shift;
6452  est = est + shift;
6453  }
6454 
6455  nleaves = j;
6456 
6457  /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6458  * overloaded
6459  */
6460  for( j = nleaves-1; j >= 0; --j )
6461  {
6462  SCIP_NODEDATA* nodedata;
6463 
6464  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6465  assert(nodedata != NULL);
6466  assert(nodedata->var != NULL);
6467 
6468  /* check if bound widening should be used */
6469  if( usebdwidening )
6470  {
6471  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6472  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6473  }
6474  else
6475  {
6476  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6477  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6478  }
6479 
6480  if( explanation != NULL )
6481  explanation[nodedata->idx] = TRUE;
6482  }
6483 
6484  (*initialized) = TRUE;
6485 
6486  return SCIP_OKAY;
6487 }
6488 
6489 /** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6490  * responsible interval bounds in *est_omega and *lct_omega
6491  */
6492 static
6493 int computeEstOmegaset(
6494  SCIP* scip, /**< SCIP data structure */
6495  int duration, /**< duration of the job to move */
6496  int demand, /**< demand of the job to move */
6497  int capacity, /**< cumulative capacity */
6498  int est, /**< earliest start time of the omega set */
6499  int lct, /**< latest start time of the omega set */
6500  int energy /**< energy of the omega set */
6501  )
6502 {
6503  int newest;
6504 
6505  newest = 0;
6506 
6507  assert(scip != NULL);
6508 
6509  if( energy > (capacity - demand) * (lct - est) )
6510  {
6511  if( energy + demand * duration > capacity * (lct - est) )
6512  {
6513  newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6514  newest += est;
6515  }
6516  }
6517 
6518  return newest;
6519 }
6520 
6521 /** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6522  *
6523  * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6524  * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6525  */
6526 static
6528  SCIP* scip, /**< SCIP data structure */
6529  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6530  SCIP_CONS* cons, /**< constraint which is propagated */
6531  SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6532  SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6533  int capacity, /**< cumulative capacity */
6534  int ncands, /**< number of candidates */
6535  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6536  int shift, /**< shift applied to all jobs before adding them to the tree */
6537  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6538  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6539  int* nchgbds, /**< pointer to store the number of bound changes */
6540  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6541  )
6542 {
6543  SCIP_NODEDATA* rootdata;
6544  int j;
6545 
6546  assert(!SCIPbtIsEmpty(tree));
6547 
6548  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6549  assert(rootdata != NULL);
6550 
6551  /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6552  for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6553  {
6554  SCIP_NODEDATA* nodedata;
6555 
6556  if( SCIPbtnodeIsRoot(leaves[j]) )
6557  break;
6558 
6559  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6560  assert(nodedata->est != -1);
6561 
6562  /* check if the root lambda envelop exeeds the available capacity */
6563  while( !(*cutoff) && rootdata->enveloplambda > capacity * nodedata->lct )
6564  {
6565  SCIP_BTNODE** omegaset;
6566  SCIP_BTNODE* leaf;
6567  SCIP_NODEDATA* leafdata;
6568  int nelements;
6569  int energy;
6570  int newest;
6571  int est;
6572  int lct;
6573 
6574  assert(!(*cutoff));
6575 
6576  /* find responsible leaf for the lambda envelope */
6578  assert(leaf != NULL);
6579  assert(SCIPbtnodeIsLeaf(leaf));
6580 
6581  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6582  assert(leafdata != NULL);
6583  assert(!leafdata->intheta);
6584  assert(leafdata->duration > 0);
6585  assert(leafdata->est >= 0);
6586 
6587  /* check if the job has to be removed since its latest completion is to large */
6588  if( leafdata->est + leafdata->duration >= nodedata->lct )
6589  {
6590  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6591 
6592  /* the root might changed therefore we need to collect the new root node data */
6593  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6594  assert(rootdata != NULL);
6595 
6596  continue;
6597  }
6598 
6599  /* compute omega set */
6600  SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6601 
6602  nelements = 0;
6603  est = INT_MAX;
6604  lct = INT_MIN;
6605  energy = 0;
6606 
6607  /* collect the omega set from theta set */
6608  traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6609  assert(nelements > 0);
6610  assert(nelements < ncands);
6611 
6612  newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6613 
6614  /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6615  if( newest > lct )
6616  {
6617  SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6618 
6619  /* analyze over load */
6620  SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6621  conshdlrdata->usebdwidening, initialized, explanation) );
6622  (*cutoff) = TRUE;
6623 
6624  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6625  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6626  }
6627  else if( newest > 0 )
6628  {
6629  SCIP_Bool infeasible;
6630  SCIP_Bool tightened;
6631  INFERINFO inferinfo;
6632 
6633  if( propest )
6634  {
6635  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6636  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6637 
6638  SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6639  SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6640 
6641  SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6642  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6643 
6644  /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6646  }
6647  else
6648  {
6649  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6650  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6651 
6652  SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6653  SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6654 
6655  SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6656  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6657 
6658  /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6660  }
6661 
6662  /* adjust the earliest start time */
6663  if( tightened )
6664  {
6665  leafdata->est = newest;
6666  (*nchgbds)++;
6667  }
6668 
6669  if( infeasible )
6670  {
6671  /* initialize conflict analysis if conflict analysis is applicable */
6673  {
6674  int i;
6675 
6676  SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6677 
6679 
6680  /* add lower and upper bound of variable which leads to the infeasibilty */
6681  SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6682  SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6683 
6684  if( explanation != NULL )
6685  explanation[leafdata->idx] = TRUE;
6686 
6687  /* add lower and upper bound of variable which lead to the infeasibilty */
6688  for( i = 0; i < nelements; ++i )
6689  {
6690  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6691  assert(nodedata != NULL);
6692 
6693  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6694  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6695 
6696  if( explanation != NULL )
6697  explanation[nodedata->idx] = TRUE;
6698  }
6699 
6700  (*initialized) = TRUE;
6701  }
6702 
6703  (*cutoff) = TRUE;
6704 
6705  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6706  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6707  }
6708  }
6709 
6710  /* free omegaset array */
6711  SCIPfreeBufferArray(scip, &omegaset);
6712 
6713  /* delete responsible leaf from lambda */
6714  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6715 
6716  /* the root might changed therefore we need to collect the new root node data */
6717  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6718  assert(rootdata != NULL);
6719  }
6720 
6721  /* move current job j from the theta set into the lambda set */
6722  SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6723  }
6724 
6725  return SCIP_OKAY;
6726 }
6727 
6728 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6729  *
6730  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6731  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6732  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6733  */
6734 static
6736  SCIP* scip, /**< SCIP data structure */
6737  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6738  int nvars, /**< number of start time variables (activities) */
6739  SCIP_VAR** vars, /**< array of start time variables */
6740  int* durations, /**< array of durations */
6741  int* demands, /**< array of demands */
6742  int capacity, /**< cumulative capacity */
6743  int hmin, /**< left bound of time axis to be considered (including hmin) */
6744  int hmax, /**< right bound of time axis to be considered (not including hmax) */
6745  SCIP_CONS* cons, /**< constraint which is propagated */
6746  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6747  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6748  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6749  int* nchgbds, /**< pointer to store the number of bound changes */
6750  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6751  )
6752 {
6753  SCIP_NODEDATA** nodedatas;
6754  SCIP_BTNODE** leaves;
6755  SCIP_BT* tree;
6756 
6757  int totalenergy;
6758  int nnodedatas;
6759  int ninsertcands;
6760  int ncands;
6761 
6762  int shift;
6763  int j;
6764 
6765  assert(scip != NULL);
6766  assert(cons != NULL);
6767  assert(initialized != NULL);
6768  assert(cutoff != NULL);
6769  assert(*cutoff == FALSE);
6770 
6771  SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6772 
6773  SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6774  SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6775 
6776  ncands = 0;
6777  totalenergy = 0;
6778 
6779  SCIP_CALL( SCIPbtCreate(&tree, SCIPblkmem(scip)) );
6780 
6781  /* compute the shift which we apply to compute .... latest completion time of all jobs */
6782  if( propest )
6783  shift = 0;
6784  else
6785  {
6786  shift = 0;
6787 
6788  /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6789  * earliest start time propagation to handle the latest completion times
6790  */
6791  for( j = 0; j < nvars; ++j )
6792  {
6793  int lct;
6794 
6795  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6796  shift = MAX(shift, lct);
6797  }
6798  }
6799 
6800  /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6801  * horizon
6802  */
6803  for( j = 0; j < nvars; ++j )
6804  {
6805  SCIP_NODEDATA* nodedata;
6806  SCIP_VAR* var;
6807  int duration;
6808  int leftadjust;
6809  int rightadjust;
6810  int energy;
6811  int est;
6812  int lct;
6813 
6814  var = vars[j];
6815  assert(var != NULL);
6816 
6817  duration = durations[j];
6818  assert(duration > 0);
6819 
6820  leftadjust = 0;
6821  rightadjust = 0;
6822 
6823  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
6824  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6825 
6826  /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6827  * effective horizon [hmin,hmax)
6828  */
6829  if( conshdlrdata->useadjustedjobs )
6830  {
6831  if( est < hmin )
6832  {
6833  leftadjust = (hmin - est);
6834  est = hmin;
6835  }
6836  if( lct > hmax )
6837  {
6838  rightadjust = (lct - hmax);
6839  lct = hmax;
6840  }
6841 
6842  /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6843  * with the effective time horizon
6844  */
6845  if( duration - leftadjust - rightadjust <= 0 )
6846  continue;
6847  }
6848  else if( est < hmin || lct > hmax )
6849  continue;
6850 
6851  energy = demands[j] * (duration - leftadjust - rightadjust);
6852  assert(energy > 0);
6853 
6854  totalenergy += energy;
6855 
6856  /* flip earliest start time and latest completion time */
6857  if( !propest )
6858  {
6859  SCIPswapInts(&est, &lct);
6860 
6861  /* shift earliest start time and latest completion time */
6862  lct = shift - lct;
6863  est = shift - est;
6864  }
6865  else
6866  {
6867  /* shift earliest start time and latest completion time */
6868  lct = lct - shift;
6869  est = est - shift;
6870  }
6871  assert(est < lct);
6872  assert(est >= 0);
6873  assert(lct >= 0);
6874 
6875  /* create search node data */
6876  SCIP_CALL( createNodedata(scip, &nodedata) );
6877 
6878  /* initialize search node data */
6879  /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6880  nodedata->key = est + j / (2.0 * nvars);
6881  nodedata->var = var;
6882  nodedata->est = est;
6883  nodedata->lct = lct;
6884  nodedata->demand = demands[j];
6885  nodedata->duration = duration;
6886  nodedata->leftadjust = leftadjust;
6887  nodedata->rightadjust = rightadjust;
6888 
6889  /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6890  * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6891  * particular time interval [a,b] against the time interval [0,b].
6892  */
6893  nodedata->enveloptheta = capacity * est + energy;
6894  nodedata->energytheta = energy;
6895  nodedata->enveloplambda = -1;
6896  nodedata->energylambda = -1;
6897 
6898  nodedata->idx = j;
6899  nodedata->intheta = TRUE;
6900 
6901  nodedatas[ncands] = nodedata;
6902  ncands++;
6903  }
6904 
6905  nnodedatas = ncands;
6906 
6907  /* sort (non-decreasing) the jobs w.r.t. latest completion times */
6908  SCIPsortPtr((void**)nodedatas, compNodedataLct, ncands);
6909 
6910  ninsertcands = 0;
6911 
6912  /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
6913  * the root envelop detects an overload
6914  */
6915  for( j = 0; j < ncands; ++j )
6916  {
6917  SCIP_BTNODE* leaf;
6918  SCIP_NODEDATA* rootdata;
6919 
6920  /* check if the new job opens a time window which size is so large that it offers more energy than the total
6921  * energy of all candidate jobs. If so we skip that one.
6922  */
6923  if( (nodedatas[j]->lct - nodedatas[j]->est) * capacity >= totalenergy )
6924  {
6925  /* set the earliest start time to minus one to mark that candidate to be not used */
6926  nodedatas[j]->est = -1;
6927  continue;
6928  }
6929 
6930  /* create search node */
6931  SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)nodedatas[j]) );
6932 
6933  /* insert new node into the theta set and updete the envelops */
6934  SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, &nnodedatas) );
6935  assert(nnodedatas <= 2*nvars);
6936 
6937  /* move the inserted candidates together */
6938  leaves[ninsertcands] = leaf;
6939  ninsertcands++;
6940 
6941  assert(!SCIPbtIsEmpty(tree));
6942  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6943  assert(rootdata != NULL);
6944 
6945  /* check if the theta set envelops exceeds the available capacity */
6946  if( rootdata->enveloptheta > capacity * nodedatas[j]->lct )
6947  {
6948  SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[j]->lct, j);
6949  (*cutoff) = TRUE;
6950 
6951  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6952  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverload++ );
6953 
6954  break;
6955  }
6956  }
6957 
6958  /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
6959  if( *cutoff )
6960  {
6961  int glbenery;
6962  int est;
6963  int lct;
6964 
6965  glbenery = 0;
6966  est = nodedatas[j]->est;
6967  lct = nodedatas[j]->lct;
6968 
6969  /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
6970  * which led to an overload
6971  */
6972  for( j = j+1; j < ncands; ++j )
6973  {
6974  SCIP_NODEDATA* nodedata;
6975  int duration;
6976  int glbest;
6977  int glblct;
6978 
6979  nodedata = nodedatas[j];
6980  assert(nodedata != NULL);
6981 
6982  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6983 
6984  /* get latest start time */
6985  glbest = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(nodedata->var));
6986  glblct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
6987 
6988  /* check if parts of the jobs run with the time window defined by the last inserted job */
6989  if( glbest < est )
6990  duration -= (est - glbest);
6991 
6992  if( glblct > lct )
6993  duration -= (glblct - lct);
6994 
6995  if( duration > 0 )
6996  {
6997  glbenery += nodedata->demand * duration;
6998 
6999  if( explanation != NULL )
7000  explanation[nodedata->idx] = TRUE;
7001  }
7002  }
7003 
7004  /* analyze the overload */
7005  SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7006  conshdlrdata->usebdwidening, initialized, explanation) );
7007  }
7008  else if( ninsertcands > 1 && conshdlrdata->efinfer )
7009  {
7010  /* if we have more than one job insterted and edge-finding should be performed we do it */
7011  SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7012  propest, shift, initialized, explanation, nchgbds, cutoff) );
7013  }
7014 
7015  /* free the search nodes data */
7016  for( j = nnodedatas - 1; j >= 0; --j )
7017  {
7018  freeNodedata(scip, &nodedatas[j]);
7019  }
7020 
7021  /* free theta tree */
7022  SCIPbtFree(&tree);
7023 
7024  /* free buffer arrays */
7025  SCIPfreeBufferArray(scip, &leaves);
7026  SCIPfreeBufferArray(scip, &nodedatas);
7027 
7028  return SCIP_OKAY;
7029 }
7030 
7031 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7032  *
7033  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7034  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7035  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7036  */
7037 static
7039  SCIP* scip, /**< SCIP data structure */
7040  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7041  int nvars, /**< number of start time variables (activities) */
7042  SCIP_VAR** vars, /**< array of start time variables */
7043  int* durations, /**< array of durations */
7044  int* demands, /**< array of demands */
7045  int capacity, /**< cumulative capacity */
7046  int hmin, /**< left bound of time axis to be considered (including hmin) */
7047  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7048  SCIP_CONS* cons, /**< constraint which is propagated */
7049  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7050  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7051  int* nchgbds, /**< pointer to store the number of bound changes */
7052  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7053  )
7054 {
7055  /* check if a cutoff was already detected */
7056  if( (*cutoff) )
7057  return SCIP_OKAY;
7058 
7059  /* check if at least the basic overload checking should be preformed */
7060  if( !conshdlrdata->efcheck )
7061  return SCIP_OKAY;
7062 
7063  /* check for overload, which may result in a cutoff */
7064  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7065  cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7066 
7067  /* check if a cutoff was detected */
7068  if( (*cutoff) )
7069  return SCIP_OKAY;
7070 
7071  /* check if bound should be infer */
7072  if( !conshdlrdata->efinfer )
7073  return SCIP_OKAY;
7074 
7075  /* check for overload, which may result in a cutoff */
7076  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7077  cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7078 
7079  return SCIP_OKAY;
7080 }
7081 
7082 /** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7083  * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7084  * event points
7085  */
7086 static
7088  SCIP* scip, /**< SCIP data structure */
7089  int nvars, /**< number of start time variables (activities) */
7090  SCIP_VAR** vars, /**< array of start time variables */
7091  int* durations, /**< array of durations */
7092  int* demands, /**< array of demands */
7093  int capacity, /**< cumulative capacity */
7094  int hmin, /**< left bound of time axis to be considered (including hmin) */
7095  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7096  SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7097  )
7098 {
7099 
7100  SCIP_VAR* var;
7101  int* starttimes; /* stores when each job is starting */
7102  int* endtimes; /* stores when each job ends */
7103  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7104  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7105 
7106  int lb;
7107  int ub;
7108  int freecapacity; /* remaining capacity */
7109  int curtime; /* point in time which we are just checking */
7110  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7111  int njobs;
7112  int j;
7113 
7114  assert(scip != NULL);
7115  assert(redundant != NULL);
7116 
7117  (*redundant) = TRUE;
7118 
7119  /* if no activities are associated with this cumulative then this constraint is redundant */
7120  if( nvars == 0 )
7121  return SCIP_OKAY;
7122 
7123  assert(vars != NULL);
7124 
7125  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7126  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7127  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7128  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7129 
7130  njobs = 0;
7131 
7132  /* assign variables, start and endpoints to arrays */
7133  for( j = 0; j < nvars; ++j )
7134  {
7135  assert(durations[j] > 0);
7136  assert(demands[j] > 0);
7137 
7138  var = vars[j];
7139  assert(var != NULL);
7140 
7141  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7142  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7143 
7144  /* check if jobs runs completely outside of the effective time horizon */
7145  if( lb >= hmax || ub + durations[j] <= hmin )
7146  continue;
7147 
7148  starttimes[njobs] = MAX(lb, hmin);
7149  startindices[njobs] = j;
7150 
7151  endtimes[njobs] = MIN(ub + durations[j], hmax);
7152  endindices[njobs] = j;
7153  assert(starttimes[njobs] <= endtimes[njobs]);
7154  njobs++;
7155  }
7156 
7157  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7158  SCIPsortIntInt(starttimes, startindices, njobs);
7159  SCIPsortIntInt(endtimes, endindices, njobs);
7160 
7161  endindex = 0;
7162  freecapacity = capacity;
7163 
7164  /* check each start point of a job whether the capacity is violated or not */
7165  for( j = 0; j < njobs; ++j )
7166  {
7167  curtime = starttimes[j];
7168 
7169  /* stop checking, if time point is above hmax */
7170  if( curtime >= hmax )
7171  break;
7172 
7173  /* subtract all capacity needed up to this point */
7174  freecapacity -= demands[startindices[j]];
7175  while( j+1 < njobs && starttimes[j+1] == curtime )
7176  {
7177  ++j;
7178  freecapacity -= demands[startindices[j]];
7179  }
7180 
7181  /* free all capacity usages of jobs the are no longer running */
7182  while( endtimes[endindex] <= curtime )
7183  {
7184  freecapacity += demands[endindices[endindex]];
7185  ++endindex;
7186  }
7187  assert(freecapacity <= capacity);
7188 
7189  /* check freecapacity to be smaller than zero */
7190  if( freecapacity < 0 && curtime >= hmin )
7191  {
7192  (*redundant) = FALSE;
7193  break;
7194  }
7195  } /*lint --e{850}*/
7196 
7197  /* free all buffer arrays */
7198  SCIPfreeBufferArray(scip, &endindices);
7199  SCIPfreeBufferArray(scip, &startindices);
7200  SCIPfreeBufferArray(scip, &endtimes);
7201  SCIPfreeBufferArray(scip, &starttimes);
7202 
7203  return SCIP_OKAY;
7204 }
7205 
7206 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7207  * completion time
7208  */
7209 static
7211  SCIP* scip, /**< SCIP data structure */
7212  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7213  SCIP_PROFILE* profile, /**< resource profile */
7214  int nvars, /**< number of variables (jobs) */
7215  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7216  int* durations, /**< array containing corresponding durations */
7217  int* demands, /**< array containing corresponding demands */
7218  int capacity, /**< cumulative capacity */
7219  int hmin, /**< left bound of time axis to be considered (including hmin) */
7220  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7221  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7222  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7223  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7224  )
7225 {
7226  int v;
7227 
7228  /* insert all cores */
7229  for( v = 0; v < nvars; ++v )
7230  {
7231  SCIP_VAR* var;
7232  SCIP_Bool infeasible;
7233  int duration;
7234  int demand;
7235  int begin;
7236  int end;
7237  int est;
7238  int lst;
7239  int pos;
7240 
7241  var = vars[v];
7242  assert(var != NULL);
7243  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(var)));
7244  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(var)));
7245 
7246  duration = durations[v];
7247  assert(duration > 0);
7248 
7249  demand = demands[v];
7250  assert(demand > 0);
7251 
7252  /* collect earliest and latest start time */
7253  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7254  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7255 
7256  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7257  if( lst + duration <= hmin || est >= hmax )
7258  continue;
7259 
7260  /* compute core interval w.r.t. effective time horizon */
7261  begin = MAX(hmin, lst);
7262  end = MIN(hmax, est + duration);
7263 
7264  /* check if a core exists */
7265  if( begin >= end )
7266  continue;
7267 
7268  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7269  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7270 
7271  /* insert the core into core resource profile (complexity O(log n)) */
7272  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7273 
7274  /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7275  if( infeasible )
7276  {
7277  assert(begin <= SCIPprofileGetTime(profile, pos));
7278  assert(end > SCIPprofileGetTime(profile, pos));
7279 
7280  /* use conflict analysis to analysis the core insertion which was infeasible */
7281  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7282  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7283 
7284  if( explanation != NULL )
7285  explanation[v] = TRUE;
7286 
7287  (*cutoff) = TRUE;
7288 
7289  /* for the statistic we count the number of times a cutoff was detected due the time-time */
7290  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
7291 
7292  break;
7293  }
7294  }
7295 
7296  return SCIP_OKAY;
7297 }
7298 
7299 /** propagate the cumulative condition */
7300 static
7302  SCIP* scip, /**< SCIP data structure */
7303  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7304  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7305  int nvars, /**< number of start time variables (activities) */
7306  SCIP_VAR** vars, /**< array of start time variables */
7307  int* durations, /**< array of durations */
7308  int* demands, /**< array of demands */
7309  int capacity, /**< cumulative capacity */
7310  int hmin, /**< left bound of time axis to be considered (including hmin) */
7311  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7312  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7313  int* nchgbds, /**< pointer to store the number of bound changes */
7314  SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7315  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7316  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7317  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7318  )
7319 {
7320  SCIP_PROFILE* profile;
7321 
7322  SCIP_RETCODE retcode = SCIP_OKAY;
7323 
7324  assert(nchgbds != NULL);
7325  assert(initialized != NULL);
7326  assert(cutoff != NULL);
7327  assert(!(*cutoff));
7328 
7329  /**@todo avoid always sorting the variable array */
7330 
7331  /* check if the constraint is redundant */
7332  SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7333 
7334  if( *redundant )
7335  return SCIP_OKAY;
7336 
7337  /* create an empty resource profile for profiling the cores of the jobs */
7338  SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7339 
7340  /* create core profile (compulsory parts) */
7341  SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7342  initialized, explanation, cutoff), TERMINATE );
7343 
7344  /* propagate the job cores until nothing else can be detected */
7345  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7346  {
7347  SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7348  nchgbds, initialized, explanation, cutoff), TERMINATE );
7349  }
7350 
7351  /* run edge finding propagator */
7352  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7353  {
7354  SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7355  cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7356  }
7357 
7358  /* run time-table edge-finding propagator */
7359  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7360  {
7361  SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7362  nchgbds, initialized, explanation, cutoff), TERMINATE );
7363  }
7364  /* free resource profile */
7365  /* cppcheck-suppress unusedLabel */
7366 TERMINATE:
7367  SCIPprofileFree(&profile);
7368 
7369  return retcode;
7370 }
7371 
7372 /** propagate the cumulative constraint */
7373 static
7375  SCIP* scip, /**< SCIP data structure */
7376  SCIP_CONS* cons, /**< constraint to propagate */
7377  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7378  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7379  int* nchgbds, /**< pointer to store the number of bound changes */
7380  int* ndelconss, /**< pointer to store the number of deleted constraints */
7381  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7382  )
7383 {
7384  SCIP_CONSDATA* consdata;
7385  SCIP_Bool initialized;
7386  SCIP_Bool redundant;
7387  int oldnchgbds;
7388 
7389  assert(scip != NULL);
7390  assert(cons != NULL);
7391 
7392  consdata = SCIPconsGetData(cons);
7393  assert(consdata != NULL);
7394 
7395  oldnchgbds = *nchgbds;
7396  initialized = FALSE;
7397  redundant = FALSE;
7398 
7399  if( SCIPconsIsDeleted(cons) )
7400  {
7401  assert(SCIPinProbing(scip));
7402  return SCIP_OKAY;
7403  }
7404 
7405  /* if the constraint marked to be propagated, do nothing */
7406  if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7407  return SCIP_OKAY;
7408 
7409  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7410  consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7411  consdata->hmin, consdata->hmax, cons,
7412  nchgbds, &redundant, &initialized, NULL, cutoff) );
7413 
7414  if( redundant )
7415  {
7416  SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7417  SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7418 
7419  if( !SCIPinProbing(scip) )
7420  {
7421  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7422  (*ndelconss)++;
7423  }
7424  }
7425  else
7426  {
7427  if( initialized )
7428  {
7429  /* run conflict analysis since it was initialized */
7430  assert(*cutoff == TRUE);
7431  SCIPdebugMsg(scip, "start conflict analysis\n");
7432  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7433  }
7434 
7435  /* if successful, reset age of constraint */
7436  if( *cutoff || *nchgbds > oldnchgbds )
7437  {
7438  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7439  }
7440  else
7441  {
7442  /* mark the constraint to be propagated */
7443  consdata->propagated = TRUE;
7444  }
7445  }
7446 
7447  return SCIP_OKAY;
7448 }
7449 
7450 /** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7451  * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7452  * be realize as domain reduction. Otherwise we do nothing
7453  */
7454 static
7456  SCIP* scip, /**< SCIP data structure */
7457  SCIP_VAR** vars, /**< problem variables */
7458  int nvars, /**< number of problem variables */
7459  int probingpos, /**< variable number to apply probing on */
7460  SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7461  SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7462  SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7463  SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7464  SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7465  SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7466  SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7467  SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7468  SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7469  SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7470  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7471  SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7472  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7473  )
7474 {
7475  SCIP_VAR* var;
7476  SCIP_Bool tightened;
7477 
7478  assert(probingpos >= 0);
7479  assert(probingpos < nvars);
7480  assert(success != NULL);
7481  assert(cutoff != NULL);
7482 
7483  var = vars[probingpos];
7484  assert(var != NULL);
7485  assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7486  assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7487  assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7488  assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7489 
7490  (*success) = FALSE;
7491 
7492  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7493  return SCIP_OKAY;
7494 
7495  /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7496  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7497  leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7498 
7499  if( (*cutoff) )
7500  {
7501  /* note that cutoff may occur if presolving has not been executed fully */
7502  SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7503 
7504  if( tightened )
7505  {
7506  (*success) =TRUE;
7507  (*nfixedvars)++;
7508  }
7509 
7510  return SCIP_OKAY;
7511  }
7512 
7513  /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7514  * presolving has not been executed fully
7515  */
7516  if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7517  {
7518  /* note that cutoff may occur if presolving has not been executed fully */
7519  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7520 
7521  if( tightened )
7522  {
7523  (*success) = TRUE;
7524  (*nfixedvars)++;
7525  }
7526 
7527  return SCIP_OKAY;
7528  }
7529 
7530  /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7531  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7532  rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7533 
7534  if( (*cutoff) )
7535  {
7536  /* note that cutoff may occur if presolving has not been executed fully */
7537  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7538 
7539  if( tightened )
7540  {
7541  (*success) =TRUE;
7542  (*nfixedvars)++;
7543  }
7544 
7545  return SCIP_OKAY;
7546  }
7547 
7548  return SCIP_OKAY;
7549 }
7550 
7551 /** is it possible, to round variable down w.r.t. objective function */
7552 static
7554  SCIP* scip, /**< SCIP data structure */
7555  SCIP_VAR* var, /**< problem variable */
7556  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7557  )
7558 {
7559  SCIP_Real objval;
7560  int scalar;
7561 
7562  assert(roundable != NULL);
7563 
7564  *roundable = TRUE;
7565 
7566  /* a fixed variable can be definition always be safely rounded */
7568  return SCIP_OKAY;
7569 
7570  /* in case the variable is not active we need to check the object coefficient of the active variable */
7571  if( !SCIPvarIsActive(var) )
7572  {
7573  SCIP_VAR* actvar;
7574  int constant;
7575 
7576  actvar = var;
7577 
7578  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7579  assert(scalar != 0);
7580 
7581  objval = scalar * SCIPvarGetObj(actvar);
7582  }
7583  else
7584  {
7585  scalar = 1;
7586  objval = SCIPvarGetObj(var);
7587  }
7588 
7589  /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7590  * (the transformed problem is always a minimization problem)
7591  *
7592  * @note that we need to check this condition w.r.t. active variable space
7593  */
7594  if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7595  *roundable = FALSE;
7596 
7597  return SCIP_OKAY;
7598 }
7599 
7600 /** is it possible, to round variable up w.r.t. objective function */
7601 static
7603  SCIP* scip, /**< SCIP data structure */
7604  SCIP_VAR* var, /**< problem variable */
7605  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7606  )
7607 {
7608  SCIP_Real objval;
7609  int scalar;
7610 
7611  assert(roundable != NULL);
7612 
7613  *roundable = TRUE;
7614 
7615  /* a fixed variable can be definition always be safely rounded */
7617  return SCIP_OKAY;
7618 
7619  /* in case the variable is not active we need to check the object coefficient of the active variable */
7620  if( !SCIPvarIsActive(var) )
7621  {
7622  SCIP_VAR* actvar;
7623  int constant;
7624 
7625  actvar = var;
7626 
7627  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7628  assert(scalar != 0);
7629 
7630  objval = scalar * SCIPvarGetObj(actvar);
7631  }
7632  else
7633  {
7634  scalar = 1;
7635  objval = SCIPvarGetObj(var);
7636  }
7637 
7638  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7639  * (the transformed problem is always a minimization problem)
7640  *
7641  * @note that we need to check this condition w.r.t. active variable space
7642  */
7643  if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7644  *roundable = FALSE;
7645 
7646  return SCIP_OKAY;
7647 }
7648 
7649 /** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7650  * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7651  * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7652  * the only one locking this variable in the corresponding direction.
7653  */
7654 static
7656  SCIP* scip, /**< SCIP data structure */
7657  SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7658  int nconss, /**< number of cumulative constraints */
7659  SCIP_Bool local, /**< use local bounds effective horizon? */
7660  int* alternativelbs, /**< alternative lower bounds */
7661  int* alternativeubs, /**< alternative lower bounds */
7662  int* downlocks, /**< number of constraints with down lock participating by the computation */
7663  int* uplocks /**< number of constraints with up lock participating by the computation */
7664  )
7665 {
7666  int nvars;
7667  int c;
7668  int v;
7669 
7670  for( c = 0; c < nconss; ++c )
7671  {
7672  SCIP_CONSDATA* consdata;
7673  SCIP_CONS* cons;
7674  SCIP_VAR* var;
7675  int hmin;
7676  int hmax;
7677 
7678  cons = conss[c];
7679  assert(cons != NULL);
7680 
7681  /* ignore constraints which are already deletet and those which are not check constraints */
7682  if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7683  continue;
7684 
7685  consdata = SCIPconsGetData(cons);
7686  assert(consdata != NULL);
7687  assert(consdata->nvars > 1);
7688 
7689  /* compute the hmin and hmax */
7690  if( local )
7691  {
7692  SCIP_PROFILE* profile;
7693 
7694  /* create empty resource profile with infinity resource capacity */
7695  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7696 
7697  /* create worst case resource profile */
7698  SCIP_CALL( SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands) );
7699 
7700  hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7701  hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7702 
7703  /* free worst case profile */
7704  SCIPprofileFree(&profile);
7705  }
7706  else
7707  {
7708  hmin = consdata->hmin;
7709  hmax = consdata->hmax;
7710  }
7711 
7712  consdata = SCIPconsGetData(cons);
7713  assert(consdata != NULL);
7714 
7715  nvars = consdata->nvars;
7716 
7717  for( v = 0; v < nvars; ++v )
7718  {
7719  int scalar;
7720  int constant;
7721  int idx;
7722 
7723  var = consdata->vars[v];
7724  assert(var != NULL);
7725 
7726  /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7727  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR);
7728 
7729  /* ignore variable locally fixed variables */
7730  if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7731  continue;
7732 
7733 
7734  SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7735  idx = SCIPvarGetProbindex(var);
7736  assert(idx >= 0);
7737 
7738  /* first check lower bound fixing */
7739  if( consdata->downlocks[v] )
7740  {
7741  int ect;
7742  int est;
7743 
7744  /* the variable has a down locked */
7745  est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7746  ect = est + consdata->durations[v];
7747 
7748  if( ect <= hmin || hmin >= hmax )
7749  downlocks[idx]++;
7750  else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7751  {
7752  alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7753  downlocks[idx]++;
7754  }
7755  }
7756 
7757  /* second check upper bound fixing */
7758  if( consdata->uplocks[v] )
7759  {
7760  int duration;
7761  int lct;
7762  int lst;
7763 
7764  duration = consdata->durations[v];
7765 
7766  /* the variable has a up lock locked */
7767  lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7768  lct = lst + duration;
7769 
7770  if( lst >= hmax || hmin >= hmax )
7771  uplocks[idx]++;
7772  else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7773  {
7774  alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7775  uplocks[idx]++;
7776  }
7777  }
7778  }
7779  }
7780 
7781  return SCIP_OKAY;
7782 }
7783 
7784 /** apply all fixings which are given by the alternative bounds */
7785 static
7787  SCIP* scip, /**< SCIP data structure */
7788  SCIP_VAR** vars, /**< array of active variables */
7789  int nvars, /**< number of active variables */
7790  int* alternativelbs, /**< alternative lower bounds */
7791  int* alternativeubs, /**< alternative lower bounds */
7792  int* downlocks, /**< number of constraints with down lock participating by the computation */
7793  int* uplocks, /**< number of constraints with up lock participating by the computation */
7794  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7795  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7796  )
7797 {
7798  SCIP_Real* downimpllbs;
7799  SCIP_Real* downimplubs;
7800  SCIP_Real* downproplbs;
7801  SCIP_Real* downpropubs;
7802  SCIP_Real* upimpllbs;
7803  SCIP_Real* upimplubs;
7804  SCIP_Real* upproplbs;
7805  SCIP_Real* uppropubs;
7806  int v;
7807 
7808  /* get temporary memory for storing probing results */
7809  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7810  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7811  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7812  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7813  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7814  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7815  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7816  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7817 
7818  for( v = 0; v < nvars; ++v )
7819  {
7820  SCIP_VAR* var;
7821  SCIP_Bool infeasible;
7822  SCIP_Bool fixed;
7823  SCIP_Bool roundable;
7824  int ub;
7825  int lb;
7826 
7827  var = vars[v];
7828  assert(var != NULL);
7829 
7830  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7831  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7832 
7833  /* ignore fixed variables */
7834  if( ub - lb <= 0 )
7835  continue;
7836 
7837 
7838  if( SCIPvarGetNLocksDown(var) == downlocks[v] )
7839  {
7840  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7841 
7842  if( roundable )
7843  {
7844  if( alternativelbs[v] > ub )
7845  {
7846  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7847  assert(!infeasible);
7848  assert(fixed);
7849 
7850  (*nfixedvars)++;
7851 
7852  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7853  * constraints
7854  */
7855  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7856  }
7857  else
7858  {
7859  SCIP_Bool success;
7860 
7861  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7862  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7863  * infeasible we can apply the dual reduction; otherwise we do nothing
7864  */
7865  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7866  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7867  nfixedvars, &success, cutoff) );
7868 
7869  if( success )
7870  {
7871  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7872  }
7873 
7874  }
7875  }
7876  }
7877 
7878  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7879  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7880 
7881  /* ignore fixed variables */
7882  if( ub - lb <= 0 )
7883  continue;
7884 
7885  if( SCIPvarGetNLocksUp(var) == uplocks[v] )
7886  {
7887  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7888 
7889  if( roundable )
7890  {
7891  if( alternativeubs[v] < lb )
7892  {
7893  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
7894  assert(!infeasible);
7895  assert(fixed);
7896 
7897  (*nfixedvars)++;
7898 
7899  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7900  * constraints
7901  */
7902  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7903  }
7904  else
7905  {
7906  SCIP_Bool success;
7907 
7908  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7909  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7910  * infeasible we can apply the dual reduction; otherwise we do nothing
7911  */
7912  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
7913  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7914  nfixedvars, &success, cutoff) );
7915 
7916  if( success )
7917  {
7918  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7919  }
7920  }
7921  }
7922  }
7923  }
7924 
7925  /* free temporary memory */
7926  SCIPfreeBufferArray(scip, &uppropubs);
7927  SCIPfreeBufferArray(scip, &upproplbs);
7928  SCIPfreeBufferArray(scip, &upimplubs);
7929  SCIPfreeBufferArray(scip, &upimpllbs);
7930  SCIPfreeBufferArray(scip, &downpropubs);
7931  SCIPfreeBufferArray(scip, &downproplbs);
7932  SCIPfreeBufferArray(scip, &downimplubs);
7933  SCIPfreeBufferArray(scip, &downimpllbs);
7934 
7935  return SCIP_OKAY;
7936 }
7937 
7938 /** propagate all constraints together */
7939 static
7941  SCIP* scip, /**< SCIP data structure */
7942  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7943  SCIP_CONS** conss, /**< all cumulative constraint */
7944  int nconss, /**< number of cumulative constraints */
7945  SCIP_Bool local, /**< use local bounds effective horizon? */
7946  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7947  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
7948  SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
7949  )
7950 { /*lint --e{715}*/
7951  SCIP_VAR** vars;
7952  int* downlocks;
7953  int* uplocks;
7954  int* alternativelbs;
7955  int* alternativeubs;
7956  int oldnfixedvars;
7957  int nvars;
7958  int v;
7959 
7960  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7961  return SCIP_OKAY;
7962 
7963  nvars = SCIPgetNVars(scip);
7964  oldnfixedvars = *nfixedvars;
7965 
7966  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) );
7967  SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
7968  SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
7969  SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
7970  SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
7971 
7972  /* initialize arrays */
7973  for( v = 0; v < nvars; ++v )
7974  {
7975  downlocks[v] = 0;
7976  uplocks[v] = 0;
7977  alternativelbs[v] = INT_MAX;
7978  alternativeubs[v] = INT_MIN;
7979  }
7980 
7981  /* compute alternative bounds */
7982  SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
7983 
7984  /* apply fixing which result of the alternative bounds directly */
7985  SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
7986  nfixedvars, cutoff) );
7987 
7988  if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
7989  {
7990  SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
7991  }
7992 
7993  /* free all buffers */
7994  SCIPfreeBufferArray(scip, &alternativeubs);
7995  SCIPfreeBufferArray(scip, &alternativelbs);
7996  SCIPfreeBufferArray(scip, &uplocks);
7997  SCIPfreeBufferArray(scip, &downlocks);
7998  SCIPfreeBufferArray(scip, &vars);
7999 
8000  return SCIP_OKAY;
8001 }
8002 
8003 /**@} */
8004 
8005 /**@name Linear relaxations
8006  *
8007  * @{
8008  */
8009 
8010 /** creates covering cuts for jobs violating resource constraints */
8011 static
8013  SCIP* scip, /**< SCIP data structure */
8014  SCIP_CONS* cons, /**< constraint to be checked */
8015  int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8016  int time /**< at this point in time covering constraints are valid */
8017  )
8018 {
8019  SCIP_CONSDATA* consdata;
8020  SCIP_ROW* row;
8021  int* flexibleids;
8022  int* demands;
8023 
8024  char rowname[SCIP_MAXSTRLEN];
8025 
8026  int remainingcap;
8027  int smallcoversize; /* size of a small cover */
8028  int bigcoversize; /* size of a big cover */
8029  int nvars;
8030 
8031  int nflexible;
8032  int sumdemand; /* demand of all jobs up to a certain index */
8033  int j;
8034 
8035  assert(cons != NULL);
8036 
8037  /* get constraint data structure */
8038  consdata = SCIPconsGetData(cons);
8039  assert(consdata != NULL );
8040 
8041  nvars = consdata->nvars;
8042 
8043  /* sort jobs according to demands */
8044  SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8045  SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8046 
8047  nflexible = 0;
8048  remainingcap = consdata->capacity;
8049 
8050  /* get all jobs intersecting point 'time' with their bounds */
8051  for( j = 0; j < nvars; ++j )
8052  {
8053  int ub;
8054 
8055  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8056 
8057  /* only add jobs to array if they intersect with point 'time' */
8058  if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8059  {
8060  /* if job is fixed, capacity has to be decreased */
8061  if( startvalues[j] == ub )
8062  {
8063  remainingcap -= consdata->demands[j];
8064  }
8065  else
8066  {
8067  demands[nflexible] = consdata->demands[j];
8068  flexibleids[nflexible] = j;
8069  ++nflexible;
8070  }
8071  }
8072  }
8073  assert(remainingcap >= 0);
8074 
8075  /* sort demands and job ids */
8076  SCIPsortIntInt(demands, flexibleids, nflexible);
8077 
8078  /*
8079  * version 1:
8080  * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8081  * erzeuge cover constraint
8082  *
8083  */
8084 
8085  /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8086  sumdemand = 0;
8087  j = 0;
8088 
8089  while( j < nflexible && sumdemand <= remainingcap )
8090  {
8091  sumdemand += demands[j];
8092  j++;
8093  }
8094 
8095  /* j jobs form a conflict, set coversize to 'j - 1' */
8096  bigcoversize = j-1;
8097  assert(sumdemand > remainingcap);
8098  assert(bigcoversize < nflexible);
8099 
8100  /* - create a row for all jobs and their binary variables.
8101  * - at most coversize many binary variables of jobs can be set to one
8102  */
8103 
8104  /* construct row name */
8105  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8106  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8107  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8108  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8109 
8110  for( j = 0; j < nflexible; ++j )
8111  {
8112  SCIP_VAR** binvars;
8113  int* vals;
8114  int nbinvars;
8115  int idx;
8116  int start;
8117  int end;
8118  int lb;
8119  int ub;
8120  int b;
8121 
8122  idx = flexibleids[j];
8123 
8124  /* get and add binvars into var array */
8125  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8126  assert(nbinvars != 0);
8127 
8128  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8129  assert(vals != NULL);
8130 
8131  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8132  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8133 
8134  /* compute start and finishing time */
8135  start = time - consdata->durations[idx] + 1;
8136  end = MIN(time, ub);
8137 
8138  /* add all neccessary binary variables */
8139  for( b = 0; b < nbinvars; ++b )
8140  {
8141  if( vals[b] < start || vals[b] < lb )
8142  continue;
8143 
8144  if( vals[b] > end )
8145  break;
8146 
8147  assert(binvars[b] != NULL);
8148  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8149  }
8150  }
8151 
8152  /* insert and release row */
8153  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8154 
8155  if( consdata->bcoverrowssize == 0 )
8156  {
8157  consdata->bcoverrowssize = 10;
8158  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8159  }
8160  if( consdata->nbcoverrows == consdata->bcoverrowssize )
8161  {
8162  consdata->bcoverrowssize *= 2;
8163  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8164  }
8165 
8166  consdata->bcoverrows[consdata->nbcoverrows] = row;
8167  consdata->nbcoverrows++;
8168 
8169  /*
8170  * version 2:
8171  * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8172  * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8173  */
8174  /* find maximum number of jobs that can run in parallel (= coversize -1) */
8175  sumdemand = 0;
8176  j = nflexible -1;
8177  while( sumdemand <= remainingcap )
8178  {
8179  assert(j >= 0);
8180  sumdemand += demands[j];
8181  j--;
8182  }
8183 
8184  smallcoversize = nflexible - (j + 1) - 1;
8185  while( j > 0 && demands[j] == demands[nflexible-1] )
8186  --j;
8187 
8188  assert(smallcoversize < nflexible);
8189 
8190  if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8191  {
8192  /* construct row name */
8193  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8194  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8195  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8196  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8197 
8198  /* filter binary variables for each unfixed job */
8199  for( j = j + 1; j < nflexible; ++j )
8200  {
8201  SCIP_VAR** binvars;
8202  int* vals;
8203  int nbinvars;
8204  int idx;
8205  int start;
8206  int end;
8207  int lb;
8208  int ub;
8209  int b;
8210 
8211  idx = flexibleids[j];
8212 
8213  /* get and add binvars into var array */
8214  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8215  assert(nbinvars != 0);
8216 
8217  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8218  assert(vals != NULL);
8219 
8220  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8221  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8222 
8223  /* compute start and finishing time */
8224  start = time - consdata->durations[idx] + 1;
8225  end = MIN(time, ub);
8226 
8227  /* add all neccessary binary variables */
8228  for( b = 0; b < nbinvars; ++b )
8229  {
8230  if( vals[b] < start || vals[b] < lb )
8231  continue;
8232 
8233  if( vals[b] > end )
8234  break;
8235 
8236  assert(binvars[b] != NULL);
8237  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8238  }
8239  }
8240 
8241  /* insert and release row */
8242  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8243  if( consdata->scoverrowssize == 0 )
8244  {
8245  consdata->scoverrowssize = 10;
8246  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8247  }
8248  if( consdata->nscoverrows == consdata->scoverrowssize )
8249  {
8250  consdata->scoverrowssize *= 2;
8251  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8252  }
8253 
8254  consdata->scoverrows[consdata->nscoverrows] = row;
8255  consdata->nscoverrows++;
8256  }
8257 
8258  /* free buffer arrays */
8259  SCIPfreeBufferArray(scip, &flexibleids);
8260  SCIPfreeBufferArray(scip, &demands);
8261 
8262  return SCIP_OKAY;
8263 }
8264 
8265 /** method to construct cover cuts for all points in time */
8266 static
8268  SCIP* scip, /**< SCIP data structure */
8269  SCIP_CONS* cons /**< constraint to be separated */
8270  )
8271 {
8272  SCIP_CONSDATA* consdata;
8273 
8274  int* startvalues; /* stores when each job is starting */
8275  int* endvalues; /* stores when each job ends */
8276  int* startvaluessorted; /* stores when each job is starting */
8277  int* endvaluessorted; /* stores when each job ends */
8278  int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8279  int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8280 
8281  int nvars; /* number of jobs for this constraint */
8282  int freecapacity; /* remaining capacity */
8283  int curtime; /* point in time which we are just checking */
8284  int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8285 
8286  int hmin;
8287  int hmax;
8288 
8289  int j;
8290  int t;
8291 
8292  assert(scip != NULL);
8293  assert(cons != NULL);
8294 
8295  consdata = SCIPconsGetData(cons);
8296  assert(consdata != NULL);
8297 
8298  /* if no activities are associated with this resource then this constraint is redundant */
8299  if( consdata->vars == NULL )
8300  return SCIP_OKAY;
8301 
8302  nvars = consdata->nvars;
8303  hmin = consdata->hmin;
8304  hmax = consdata->hmax;
8305 
8306  SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8307  SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8308  SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8309  SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8310  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8311  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8312 
8313  /* assign start and endpoints to arrays */
8314  for ( j = 0; j < nvars; ++j )
8315  {
8316  startvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8317  startvaluessorted[j] = startvalues[j];
8318 
8319  endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8320  endvaluessorted[j] = endvalues[j];
8321 
8322  startindices[j] = j;
8323  endindices[j] = j;
8324  }
8325 
8326  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8327  * (and sort the indices in the same way) */
8328  SCIPsortIntInt(startvaluessorted, startindices, nvars);
8329  SCIPsortIntInt(endvaluessorted, endindices, nvars);
8330 
8331  endidx = 0;
8332  freecapacity = consdata->capacity;
8333 
8334  /* check each startpoint of a job whether the capacity is kept or not */
8335  for( j = 0; j < nvars; ++j )
8336  {
8337  curtime = startvaluessorted[j];
8338  if( curtime >= hmax )
8339  break;
8340 
8341  /* subtract all capacity needed up to this point */
8342  freecapacity -= consdata->demands[startindices[j]];
8343 
8344  while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8345  {
8346  ++j;
8347  freecapacity -= consdata->demands[startindices[j]];
8348  }
8349 
8350  /* free all capacity usages of jobs the are no longer running */
8351  while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8352  {
8353  freecapacity += consdata->demands[endindices[endidx]];
8354  ++endidx;
8355  }
8356 
8357  assert(freecapacity <= consdata->capacity);
8358  assert(endidx <= nvars);
8359 
8360  /* --> endindex - points to the next job which will finish
8361  * j - points to the last job that has been released
8362  */
8363 
8364 
8365  /* check freecapacity to be smaller than zero
8366  * then we will add cover constraints to the MIP
8367  */
8368  if( freecapacity < 0 && curtime >= hmin )
8369  {
8370  int nextprofilechange;
8371 
8372  /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8373  if( j < nvars-1 )
8374  nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8375  else
8376  nextprofilechange = endvaluessorted[endidx];
8377 
8378  nextprofilechange = MIN(nextprofilechange, hmax);
8379 
8380  for( t = curtime; t < nextprofilechange; ++t )
8381  {
8382  SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8383 
8384  /* create covering constraint */
8385  SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8386 
8387  }
8388  } /* end if freecapacity > 0 */
8389 
8390  } /*lint --e{850}*/
8391 
8392  consdata->covercuts = TRUE;
8393 
8394  /* free all buffer arrays */
8395  SCIPfreeBufferArray(scip, &endindices);
8396  SCIPfreeBufferArray(scip, &startindices);
8397  SCIPfreeBufferArray(scip, &endvaluessorted);
8398  SCIPfreeBufferArray(scip, &startvaluessorted);
8399  SCIPfreeBufferArray(scip, &endvalues);
8400  SCIPfreeBufferArray(scip, &startvalues);
8401 
8402  return SCIP_OKAY;
8403 }
8404 
8405 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8406  * constraint
8407  */
8408 static
8410  SCIP* scip, /**< SCIP data structure */
8411  SCIP_CONS* cons, /**< constraint to be checked */
8412  int* startindices, /**< permutation with rspect to the start times */
8413  int curtime, /**< current point in time */
8414  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8415  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8416  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8417  )
8418 {
8419  SCIP_CONSDATA* consdata;
8420  SCIP_VAR** binvars;
8421  int* coefs;
8422  int nbinvars;
8423  char name[SCIP_MAXSTRLEN];
8424  int capacity;
8425  int b;
8426 
8427  assert(nstarted > nfinished);
8428 
8429  consdata = SCIPconsGetData(cons);
8430  assert(consdata != NULL);
8431  assert(consdata->nvars > 0);
8432 
8433  capacity = consdata->capacity;
8434  assert(capacity > 0);
8435 
8436  nbinvars = 0;
8437  SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8438 
8439  /* construct row name */
8440  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8441 
8442  if( cutsasconss )
8443  {
8444  SCIP_CONS* lincons;
8445 
8446  /* create knapsack constraint for the given time point */
8447  SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8448  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) );
8449 
8450  for( b = 0; b < nbinvars; ++b )
8451  {
8452  SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8453  }
8454 
8455  /* add and release the new constraint */
8456  SCIP_CALL( SCIPaddCons(scip, lincons) );
8457  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8458  }
8459  else
8460  {
8461  SCIP_ROW* row;
8462 
8463  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8464  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8465 
8466  for( b = 0; b < nbinvars; ++b )
8467  {
8468  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8469  }
8470 
8471  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8472  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8473 
8474  if( consdata->demandrowssize == 0 )
8475  {
8476  consdata->demandrowssize = 10;
8477  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8478  }
8479  if( consdata->ndemandrows == consdata->demandrowssize )
8480  {
8481  consdata->demandrowssize *= 2;
8482  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8483  }
8484 
8485  consdata->demandrows[consdata->ndemandrows] = row;
8486  consdata->ndemandrows++;
8487  }
8488 
8489  SCIPfreeBufferArrayNull(scip, &binvars);
8490  SCIPfreeBufferArrayNull(scip, &coefs);
8491 
8492  return SCIP_OKAY;
8493 }
8494 
8495 /** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8496  * row
8497  */
8498 static
8500  SCIP* scip, /**< SCIP data structure */
8501  SCIP_CONS* cons, /**< constraint to be checked */
8502  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8503  )
8504 {
8505  SCIP_CONSDATA* consdata;
8506 
8507  int* starttimes; /* stores when each job is starting */
8508  int* endtimes; /* stores when each job ends */
8509  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8510  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8511 
8512  int nvars; /* number of activities for this constraint */
8513  int freecapacity; /* remaining capacity */
8514  int curtime; /* point in time which we are just checking */
8515  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8516 
8517  int hmin;
8518  int hmax;
8519 
8520  int j;
8521 
8522  assert(scip != NULL);
8523  assert(cons != NULL);
8524 
8525  consdata = SCIPconsGetData(cons);
8526  assert(consdata != NULL);
8527 
8528  nvars = consdata->nvars;
8529 
8530  /* if no activities are associated with this cumulative then this constraint is redundant */
8531  if( nvars == 0 )
8532  return SCIP_OKAY;
8533 
8534  assert(consdata->vars != NULL);
8535 
8536  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8537  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8538  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8539  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8540 
8541  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8542  SCIPconsGetName(cons), nvars);
8543 
8544  /* create event point arrays */
8545  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8546  starttimes, endtimes, startindices, endindices, FALSE);
8547 
8548  endindex = 0;
8549  freecapacity = consdata->capacity;
8550  hmin = consdata->hmin;
8551  hmax = consdata->hmax;
8552 
8553  /* check each startpoint of a job whether the capacity is kept or not */
8554  for( j = 0; j < nvars; ++j )
8555  {
8556  curtime = starttimes[j];
8557  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8558 
8559  if( curtime >= hmax )
8560  break;
8561 
8562  /* remove the capacity requirments for all job which start at the curtime */
8563  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8564 
8565  /* add the capacity requirments for all job which end at the curtime */
8566  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8567 
8568  assert(freecapacity <= consdata->capacity);
8569  assert(endindex <= nvars);
8570 
8571  /* endindex - points to the next job which will finish */
8572  /* j - points to the last job that has been released */
8573 
8574  /* if free capacity is smaller than zero, then add rows to the LP */
8575  if( freecapacity < 0 && curtime >= hmin )
8576  {
8577  int nextstarttime;
8578  int t;
8579 
8580  /* step forward until next job is released and see whether capacity constraint is met or not */
8581  if( j < nvars-1 )
8582  nextstarttime = starttimes[j+1];
8583  else
8584  nextstarttime = endtimes[nvars-1];
8585 
8586  nextstarttime = MIN(nextstarttime, hmax);
8587 
8588  /* create capacity restriction row for current event point */
8589  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8590 
8591  /* create for all points in time between the current event point and next start event point a row if the free
8592  * capacity is still smaller than zero */
8593  for( t = curtime+1 ; t < nextstarttime; ++t )
8594  {
8595  /* add the capacity requirments for all job which end at the curtime */
8596  addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8597 
8598  if( freecapacity < 0 )
8599  {
8600  /* add constraint */
8601  SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8602 
8603  /* create capacity restriction row */
8604  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8605  }
8606  else
8607  break;
8608  }
8609  }
8610  } /*lint --e{850}*/
8611 
8612  /* free all buffer arrays */
8613  SCIPfreeBufferArray(scip, &endindices);
8614  SCIPfreeBufferArray(scip, &startindices);
8615  SCIPfreeBufferArray(scip, &endtimes);
8616  SCIPfreeBufferArray(scip, &starttimes);
8617 
8618  return SCIP_OKAY;
8619 }
8620 
8621 /** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8622  * capacity is larger than the capacity of the cumulative constraint
8623  * - for each necessary point in time:
8624  *
8625  * sum_j sum_t demand_j * x_{j,t} <= capacity
8626  *
8627  * where x(j,t) is the binary variables of job j at time t
8628  */
8629 static
8631  SCIP* scip, /**< SCIP data structure */
8632  SCIP_CONS* cons, /**< cumulative constraint */
8633  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8634  )
8635 {
8636  SCIP_CONSDATA* consdata;
8637 
8638  consdata = SCIPconsGetData(cons);
8639  assert(consdata != NULL);
8640  assert(consdata->demandrows == NULL);
8641  assert(consdata->ndemandrows == 0);
8642 
8643  /* collect the linking constraints */
8644  if( consdata->linkingconss == NULL )
8645  {
8646  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8647  }
8648 
8649  SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8650 
8651  /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8652  if( cutsasconss )
8653  {
8654  if( SCIPconsIsInitial(cons) )
8655  {
8656  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
8657  }
8658  if( SCIPconsIsSeparated(cons) )
8659  {
8660  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
8661  }
8662  if( SCIPconsIsEnforced(cons) )
8663  {
8664  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
8665  }
8666  }
8667 
8668  return SCIP_OKAY;
8669 }
8670 
8671 /** adds linear relaxation of cumulative constraint to the LP */
8672 static
8674  SCIP* scip, /**< SCIP data structure */
8675  SCIP_CONS* cons, /**< cumulative constraint */
8676  SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
8677  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
8678  )
8679 {
8680  SCIP_CONSDATA* consdata;
8681  int r;
8682 
8683  consdata = SCIPconsGetData(cons);
8684  assert(consdata != NULL);
8685 
8686  if( consdata->demandrows == NULL )
8687  {
8688  SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8689  }
8690  assert(consdata->ndemandrows == 0 || consdata->demandrows != NULL);
8691 
8692  for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8693  {
8694  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8695  {
8696  assert(consdata->demandrows[r] != NULL);
8697  SCIP_CALL( SCIPaddCut(scip, NULL, consdata->demandrows[r], FALSE, infeasible) );
8698  }
8699  }
8700 
8701  return SCIP_OKAY;
8702 }
8703 
8704 /** checks constraint for violation, and adds it as a cut if possible */
8705 static
8707  SCIP* scip, /**< SCIP data structure */
8708  SCIP_CONS* cons, /**< cumulative constraint to be separated */
8709  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8710  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8711  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8712  )
8713 { /*lint --e{715}*/
8714  SCIP_CONSDATA* consdata;
8715  int ncuts;
8716  int r;
8717 
8718  assert(scip != NULL);
8719  assert(cons != NULL);
8720  assert(separated != NULL);
8721  assert(cutoff != NULL);
8722 
8723  *separated = FALSE;
8724  *cutoff = FALSE;
8725 
8726  consdata = SCIPconsGetData(cons);
8727  assert(consdata != NULL);
8728 
8729  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8730 
8731  if( consdata->demandrows == NULL )
8732  {
8733  SCIP_CALL( createRelaxation(scip, cons, FALSE) );
8734  }
8735  assert(consdata->ndemandrows == 0 || consdata->demandrows != NULL);
8736 
8737  ncuts = 0;
8738 
8739  /* check each row that is not contained in LP */
8740  for( r = 0; r < consdata->ndemandrows; ++r )
8741  {
8742  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8743  {
8744  SCIP_Real feasibility;
8745 
8746  if( sol != NULL )
8747  feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8748  else
8749  feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8750 
8751  if( SCIPisFeasNegative(scip, feasibility) )
8752  {
8753  SCIP_CALL( SCIPaddCut(scip, sol, consdata->demandrows[r], FALSE, cutoff) );
8754  if ( *cutoff )
8755  {
8756  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8757  return SCIP_OKAY;
8758  }
8759  *separated = TRUE;
8760  ncuts++;
8761  }
8762  }
8763  }
8764 
8765  if( ncuts > 0 )
8766  {
8767  SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8768 
8769  /* if successful, reset age of constraint */
8770  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8771  (*separated) = TRUE;
8772  }
8773 
8774  return SCIP_OKAY;
8775 }
8776 
8777 /** checks constraint for violation, and adds it as a cut if possible */
8778 static
8780  SCIP* scip, /**< SCIP data structure */
8781  SCIP_CONS* cons, /**< logic or constraint to be separated */
8782  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8783  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8784  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8785  )
8786 {
8787  SCIP_CONSDATA* consdata;
8788  SCIP_ROW* row;
8789  SCIP_Real minfeasibility;
8790  int r;
8791 
8792  assert(scip != NULL);
8793  assert(cons != NULL);
8794  assert(separated != NULL);
8795  assert(cutoff != NULL);
8796 
8797  *separated = FALSE;
8798  *cutoff = FALSE;
8799 
8800  consdata = SCIPconsGetData(cons);
8801  assert(consdata != NULL);
8802 
8803  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8804 
8805  /* collect the linking constraints */
8806  if( consdata->linkingconss == NULL )
8807  {
8808  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8809  }
8810 
8811  if( !consdata->covercuts )
8812  {
8813  SCIP_CALL( createCoverCuts(scip, cons) );
8814  }
8815 
8816  row = NULL;
8817  minfeasibility = SCIPinfinity(scip);
8818 
8819  /* check each row of small covers that is not contained in LP */
8820  for( r = 0; r < consdata->nscoverrows; ++r )
8821  {
8822  if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8823  {
8824  SCIP_Real feasibility;
8825 
8826  assert(consdata->scoverrows[r] != NULL);
8827  if( sol != NULL )
8828  feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8829  else
8830  feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8831 
8832  if( minfeasibility > feasibility )
8833  {
8834  minfeasibility = feasibility;
8835  row = consdata->scoverrows[r];
8836  }
8837  }
8838  }
8839 
8840  if( SCIPisFeasNegative(scip, minfeasibility) )
8841  {
8842  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8843  SCIPconsGetName(cons), minfeasibility);
8844 
8845  assert(row != NULL);
8846  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, cutoff) );
8847  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8848  if ( *cutoff )
8849  return SCIP_OKAY;
8850  (*separated) = TRUE;
8851  }
8852 
8853  minfeasibility = SCIPinfinity(scip);
8854  row = NULL;
8855 
8856  /* check each row of small covers that is not contained in LP */
8857  for( r = 0; r < consdata->nbcoverrows; ++r )
8858  {
8859  if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8860  {
8861  SCIP_Real feasibility;
8862 
8863  assert(consdata->bcoverrows[r] != NULL);
8864  if( sol != NULL )
8865  feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8866  else
8867  feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8868 
8869  if( minfeasibility > feasibility )
8870  {
8871  minfeasibility = feasibility;
8872  row = consdata->bcoverrows[r];
8873  }
8874  }
8875  }
8876 
8877  if( SCIPisFeasNegative(scip, minfeasibility) )
8878  {
8879  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8880  SCIPconsGetName(cons), minfeasibility);
8881 
8882  assert(row != NULL);
8883  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, cutoff) );
8884  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8885  if ( *cutoff )
8886  return SCIP_OKAY;
8887  (*separated) = TRUE;
8888  }
8889 
8890  return SCIP_OKAY;
8891 }
8892 
8893 /** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
8894 static
8896  SCIP* scip, /**< SCIP data structure */
8897  SCIP_CONS* cons, /**< constraint to be checked */
8898  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8899  int* startindices, /**< permutation with rspect to the start times */
8900  int curtime, /**< current point in time */
8901  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8902  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8903  SCIP_Bool lower /**< shall cuts be created due to lower or upper bounds? */
8904  )
8905 {
8906  SCIP_CONSDATA* consdata;
8907  char name[SCIP_MAXSTRLEN];
8908  SCIP_Bool infeasible;
8909  int lhs; /* left hand side of constraint */
8910 
8911  SCIP_VAR** activevars;
8912  SCIP_ROW* row;
8913 
8914  int v;
8915 
8916  assert(nstarted > nfinished);
8917 
8918  consdata = SCIPconsGetData(cons);
8919  assert(consdata != NULL);
8920  assert(consdata->nvars > 0);
8921 
8922 
8923  SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
8924 
8925  SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
8926 
8927  if( lower )
8928  {
8929  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
8930 
8931  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, (SCIP_Real) lhs, SCIPinfinity(scip),
8932  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8933  }
8934  else
8935  {
8936  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
8937  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real) lhs,
8938  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8939  }
8940 
8941  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8942 
8943  for( v = 0; v < nstarted - nfinished; ++v )
8944  {
8945  SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
8946  }
8947 
8948  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8949  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8950 
8951  SCIP_CALL( SCIPaddCut(scip, sol, row, TRUE, &infeasible) );
8952  assert( ! infeasible );
8953 
8954  SCIP_CALL( SCIPreleaseRow(scip, &row) );
8955 
8956  /* free buffers */
8957  SCIPfreeBufferArrayNull(scip, &activevars);
8958 
8959  return SCIP_OKAY;
8960 }
8961 
8962 /** checks constraint for violation, and adds it as a cut if possible */
8963 static
8965  SCIP* scip, /**< SCIP data structure */
8966  SCIP_CONS* cons, /**< cumulative constraint to be separated */
8967  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8968  SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
8969  SCIP_Bool* separated /**< pointer to store TRUE, if a cut was found */
8970  )
8971 {
8972 
8973  SCIP_CONSDATA* consdata;
8974 
8975  int* starttimes; /* stores when each job is starting */
8976  int* endtimes; /* stores when each job ends */
8977  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8978  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8979 
8980  int nvars; /* number of activities for this constraint */
8981  int freecapacity; /* remaining capacity */
8982  int curtime; /* point in time which we are just checking */
8983  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8984 
8985  int hmin;
8986  int hmax;
8987  int j;
8988 
8989  assert(scip != NULL);
8990  assert(cons != NULL);
8991 
8992  consdata = SCIPconsGetData(cons);
8993  assert(consdata != NULL);
8994 
8995  nvars = consdata->nvars;
8996 
8997  /* if no activities are associated with this cumulative then this constraint is redundant */
8998  if( nvars <= 1 )
8999  return SCIP_OKAY;
9000 
9001  assert(consdata->vars != NULL);
9002 
9003  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
9004  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
9005  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9006  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9007 
9008  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9009  SCIPconsGetName(cons), nvars);
9010 
9011  /* create event point arrays */
9012  createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9013 
9014  /* now nvars might be smaller than before! */
9015 
9016  endindex = 0;
9017  freecapacity = consdata->capacity;
9018  hmin = consdata->hmin;
9019  hmax = consdata->hmax;
9020 
9021  /* check each startpoint of a job whether the capacity is kept or not */
9022  for( j = 0; j < nvars; ++j )
9023  {
9024  curtime = starttimes[j];
9025 
9026  if( curtime >= hmax )
9027  break;
9028 
9029  /* remove the capacity requirements for all job which start at the curtime */
9030  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9031 
9032  /* add the capacity requirments for all job which end at the curtime */
9033  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9034 
9035  assert(freecapacity <= consdata->capacity);
9036  assert(endindex <= nvars);
9037 
9038  /* endindex - points to the next job which will finish */
9039  /* j - points to the last job that has been released */
9040 
9041  /* if free capacity is smaller than zero, then add rows to the LP */
9042  if( freecapacity < 0 && curtime >= hmin)
9043  {
9044  /* create capacity restriction row for current event point */
9045  SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, sol, startindices, curtime, j+1, endindex, lower) );
9046  *separated = TRUE;
9047  }
9048  } /*lint --e{850}*/
9049 
9050  /* free all buffer arrays */
9051  SCIPfreeBufferArray(scip, &endindices);
9052  SCIPfreeBufferArray(scip, &startindices);
9053  SCIPfreeBufferArray(scip, &endtimes);
9054  SCIPfreeBufferArray(scip, &starttimes);
9055 
9056  return SCIP_OKAY;
9057 }
9058 
9059 /**@} */
9060 
9061 
9062 /**@name Presolving
9063  *
9064  * @{
9065  */
9066 
9067 #ifndef NDEBUG
9068 /** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9069  * correct
9070  */
9071 static
9073  SCIP* scip, /**< SCIP data structure */
9074  SCIP_CONS* cons /**< constraint to be checked */
9075  )
9076 {
9077  SCIP_CONSDATA* consdata;
9078  int capacity;
9079  int nvars;
9080  int j;
9081 
9082  assert(scip != NULL);
9083  assert(cons != NULL);
9084 
9085  consdata = SCIPconsGetData(cons);
9086  assert(consdata != NULL);
9087 
9088  nvars = consdata->nvars;
9089 
9090  /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9091  if( nvars <= 1 )
9092  return TRUE;
9093 
9094  assert(consdata->vars != NULL);
9095  capacity = consdata->capacity;
9096 
9097  /* check each activity: if demand is larger than capacity the problem is infeasible */
9098  for ( j = 0; j < nvars; ++j )
9099  {
9100  if( consdata->demands[j] > capacity )
9101  return FALSE;
9102  }
9103 
9104  return TRUE;
9105 }
9106 #endif
9107 
9108 /** delete constraint if it consists of at most one job
9109  *
9110  * @todo this method needs to be adjusted w.r.t. effective horizon
9111  */
9112 static
9114  SCIP* scip, /**< SCIP data structure */
9115  SCIP_CONS* cons, /**< constraint to propagate */
9116  int* ndelconss, /**< pointer to store the number of deleted constraints */
9117  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9118  )
9119 {
9120  SCIP_CONSDATA* consdata;
9121 
9122  assert(scip != NULL);
9123  assert(cons != NULL);
9124 
9125  consdata = SCIPconsGetData(cons);
9126  assert(consdata != NULL);
9127 
9128  if( consdata->nvars == 0 )
9129  {
9130  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9131 
9132  SCIP_CALL( SCIPdelCons(scip, cons) );
9133  (*ndelconss)++;
9134  }
9135  else if( consdata->nvars == 1 )
9136  {
9137  if( consdata->demands[0] > consdata->capacity )
9138  (*cutoff) = TRUE;
9139  else
9140  {
9141  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9142 
9143  SCIP_CALL( SCIPdelCons(scip, cons) );
9144  (*ndelconss)++;
9145  }
9146  }
9147 
9148  return SCIP_OKAY;
9149 }
9150 
9151 /** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9152  * this is done in the SCIP_DECL_CONSINITPRE() callback
9153  */
9154 static
9156  SCIP* scip, /**< SCIP data structure */
9157  SCIP_CONS* cons /**< constraint to propagate */
9158  )
9159 {
9160  SCIP_CONSDATA* consdata;
9161  SCIP_VAR* var;
9162  int demand;
9163  int duration;
9164  int hmin;
9165  int hmax;
9166  int est;
9167  int lct;
9168  int j;
9169 
9170  assert(scip != NULL);
9171  assert(cons != NULL);
9172 
9173  consdata = SCIPconsGetData(cons);
9174  assert(consdata != NULL);
9175 
9176  hmin = consdata->hmin;
9177  hmax = consdata->hmax;
9178 
9179  SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9180  SCIPconsGetName(cons), hmin, hmax);
9181 
9182  for( j = consdata->nvars-1; j >= 0; --j )
9183  {
9184  var = consdata->vars[j];
9185  demand = consdata->demands[j];
9186  duration = consdata->durations[j];
9187 
9188  /* earliest completion time (ect) and latest start time (lst) */
9189  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9190  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9191 
9192  if( demand == 0 || duration == 0 )
9193  {
9194  /* jobs with zero demand or zero duration can be removed */
9195  SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
9196  SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9197 
9198  /* remove variable form constraint */
9199  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9200  }
9201  else if( est >= hmax || lct <= hmin )
9202  {
9203  SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
9204  SCIPvarGetName(var), est, lct - duration, duration);
9205 
9206  /* delete variable at the given position */
9207  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9208 
9209  /* for the statistic we count the number of jobs which are irrelevant */
9210  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9211  }
9212  }
9213 
9214  return SCIP_OKAY;
9215 }
9216 
9217 /** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9218 static
9220  SCIP* scip, /**< SCIP data structure */
9221  SCIP_CONSDATA* consdata, /**< constraint data */
9222  int pos, /**< position of job in the consdata */
9223  int* nchgbds, /**< pointer to store the number of changed bounds */
9224  int* naddconss, /**< pointer to store the number of added constraints */
9225  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9226  )
9227 {
9228  SCIP_VAR* var;
9229  SCIP_Bool tightened;
9230  int duration;
9231  int ect;
9232  int lst;
9233 
9234  assert(scip != NULL);
9235 
9236  /* zero energy jobs should be removed already */
9237  assert(consdata->durations[pos] > 0);
9238  assert(consdata->demands[pos] > 0);
9239 
9240  var = consdata->vars[pos];
9241  assert(var != NULL);
9242  duration = consdata->durations[pos];
9243 
9244  /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9245  SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9246  SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9247 
9248  /* earliest completion time (ect) and latest start time (lst) */
9249  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9250  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9251 
9252  /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9253  if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9254  return SCIP_OKAY;
9255 
9256  if( ect > consdata->hmin && lst < consdata->hmax )
9257  {
9258  /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9259  *cutoff = TRUE;
9260  }
9261  else if( lst < consdata->hmax )
9262  {
9263  /* move the latest start time of this job in such a way that it finishes before or at hmin */
9264  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9265  assert(tightened);
9266  assert(!(*cutoff));
9267  (*nchgbds)++;
9268  }
9269  else if( ect > consdata->hmin )
9270  {
9271  /* move the earliest start time of this job in such a way that it starts after or at hmax */
9272  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9273  assert(tightened);
9274  assert(!(*cutoff));
9275  (*nchgbds)++;
9276  }
9277  else
9278  {
9279  /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9280  * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9281  *
9282  * (var <= hmin - duration) /\ (var >= hmax)
9283  */
9284  SCIP_CONS* cons;
9285 
9286  SCIP_VAR* vartuple[2];
9287  SCIP_BOUNDTYPE boundtypetuple[2];
9288  SCIP_Real boundtuple[2];
9289 
9290  char name[SCIP_MAXSTRLEN];
9291  int leftbound;
9292  int rightbound;
9293 
9294  leftbound = consdata->hmin - duration;
9295  rightbound = consdata->hmax;
9296 
9297  /* allocate temporary memory for arrays */
9298  vartuple[0] = var;
9299  vartuple[1] = var;
9300  boundtuple[0] = (SCIP_Real)leftbound;
9301  boundtuple[1] = (SCIP_Real)rightbound;
9302  boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9303  boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9304 
9305  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9306  SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9307 
9308  /* create and add bounddisjunction constraint */
9309  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9310  TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9311 
9312  SCIPdebugPrintCons(scip, cons, NULL);
9313 
9314  /* add and release the new constraint */
9315  SCIP_CALL( SCIPaddCons(scip, cons) );
9316  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9317  (*naddconss)++;
9318  }
9319 
9320  return SCIP_OKAY;
9321 }
9322 
9323 /** try to removed over sizeed jobs (the demand is larger than the capacity) */
9324 static
9326  SCIP* scip, /**< SCIP data structure */
9327  SCIP_CONS* cons, /**< constraint */
9328  int* nchgbds, /**< pointer to store the number of changed bounds */
9329  int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9330  int* naddconss, /**< pointer to store the number of added constraints */
9331  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9332  )
9333 {
9334  SCIP_CONSDATA* consdata;
9335  int capacity;
9336  int j;
9337 
9338  consdata = SCIPconsGetData(cons);
9339  assert(consdata != NULL);
9340 
9341  /* if a cutoff was already detected just return */
9342  if( *cutoff )
9343  return SCIP_OKAY;
9344 
9345  capacity = consdata->capacity;
9346 
9347  for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9348  {
9349  if( consdata->demands[j] > capacity )
9350  {
9351  SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9352 
9353  /* remove variable form constraint */
9354  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9355  (*nchgcoefs)++;
9356  }
9357  }
9358 
9359  SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9360 
9361  return SCIP_OKAY;
9362 }
9363 
9364 /** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9365 static
9367  SCIP* scip, /**< SCIP data structure */
9368  SCIP_VAR* var, /**< integer variable to fix */
9369  SCIP_Bool uplock, /**< has thet start time variable a up lock */
9370  int* nfixedvars /**< pointer to store the number fixed variables */
9371  )
9372 {
9373  SCIP_Bool infeasible;
9374  SCIP_Bool tightened;
9375  SCIP_Bool roundable;
9376 
9377  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9378  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9379  */
9380  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9381  return SCIP_OKAY;
9382 
9383  /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9384  * handler is the only one locking that variable up
9385  */
9386  assert(uplock == TRUE || uplock == FALSE);
9387  assert((int)TRUE == 1);
9388  assert((int)FALSE == 0);
9389 
9390  if( SCIPvarGetNLocksUp(var) > (int)(uplock) )
9391  return SCIP_OKAY;
9392 
9393  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9394 
9395  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9396  * (the transformed problem is always a minimization problem)
9397  */
9398  if( !roundable )
9399  return SCIP_OKAY;
9400 
9401  SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9403 
9404  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9405  assert(!infeasible);
9406 
9407  if( tightened )
9408  {
9409  SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9410  (*nfixedvars)++;
9411  }
9412 
9413  return SCIP_OKAY;
9414 }
9415 
9416 /** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9417 static
9419  SCIP* scip, /**< SCIP data structure */
9420  SCIP_VAR* var, /**< integer variable to fix */
9421  SCIP_Bool downlock, /**< has the variable a down lock */
9422  int* nfixedvars /**< pointer to store the number fixed variables */
9423  )
9424 {
9425  SCIP_Bool infeasible;
9426  SCIP_Bool tightened;
9427  SCIP_Bool roundable;
9428 
9429  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9430  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9431  */
9432  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9433  return SCIP_OKAY;
9434 
9435  /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9436  * handler is the only one locking that variable down
9437  */
9438  assert(downlock == TRUE || downlock == FALSE);
9439  assert((int)TRUE == 1);
9440  assert((int)FALSE == 0);
9441 
9442  if( SCIPvarGetNLocksDown(var) > (int)(downlock) )
9443  return SCIP_OKAY;
9444 
9445  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9446 
9447  /* is it possible, to round variable down w.r.t. objective function? */
9448  if( !roundable )
9449  return SCIP_OKAY;
9450 
9451  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9452  assert(!infeasible);
9453 
9454  if( tightened )
9455  {
9456  SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9457  (*nfixedvars)++;
9458  }
9459 
9460  return SCIP_OKAY;
9461 }
9462 
9463 /** normalize cumulative condition */
9464 static
9466  SCIP* scip, /**< SCIP data structure */
9467  int nvars, /**< number of start time variables (activities) */
9468  SCIP_VAR** vars, /**< array of start time variables */
9469  int* durations, /**< array of durations */
9470  int* demands, /**< array of demands */
9471  int* capacity, /**< pointer to store the changed cumulative capacity */
9472  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9473  int* nchgsides /**< pointer to count number of side changes */
9474  )
9475 { /*lint --e{715}*/
9476  SCIP_Longint gcd;
9477  int mindemand1;
9478  int mindemand2;
9479  int v;
9480 
9481  if( *capacity == 1 || nvars <= 1 )
9482  return SCIP_OKAY;
9483 
9484  assert(demands[nvars-1] <= *capacity);
9485  assert(demands[nvars-2] <= *capacity);
9486 
9487  gcd = (SCIP_Longint)demands[nvars-1];
9488  mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9489  mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9490 
9491  for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9492  {
9493  assert(mindemand1 <= mindemand2);
9494  assert(demands[v] <= *capacity);
9495 
9496  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9497 
9498  if( mindemand1 > demands[v] )
9499  {
9500  mindemand2 = mindemand1;
9501  mindemand1 = demands[v];
9502  }
9503  else if( mindemand2 > demands[v] )
9504  mindemand2 = demands[v];
9505  }
9506 
9507  if( mindemand1 + mindemand2 > *capacity )
9508  {
9509  SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9510 
9511  for( v = 0; v < nvars; ++v )
9512  demands[v] = 1;
9513 
9514  (*capacity) = 1;
9515 
9516  (*nchgcoefs) += nvars;
9517  (*nchgsides)++;
9518  }
9519  else if( gcd >= 2 )
9520  {
9521  SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9522 
9523  for( v = 0; v < nvars; ++v )
9524  demands[v] /= gcd;
9525 
9526  (*capacity) /= gcd;
9527 
9528  (*nchgcoefs) += nvars;
9529  (*nchgsides)++;
9530  }
9531 
9532  return SCIP_OKAY;
9533 }
9534 
9535 /** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9536  * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9537  * capacity since in that case none of the jobs can run in parallel
9538  */
9539 static
9541  SCIP* scip, /**< SCIP data structure */
9542  SCIP_CONS* cons, /**< cumulative constraint */
9543  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9544  int* nchgsides /**< pointer to count number of side changes */
9545  )
9546 {
9547  SCIP_CONSDATA* consdata;
9548  int capacity;
9549 
9550  assert(nchgcoefs != NULL);
9551  assert(nchgsides != NULL);
9552  assert(!SCIPconsIsModifiable(cons));
9553 
9554  consdata = SCIPconsGetData(cons);
9555  assert(consdata != NULL);
9556 
9557  if( consdata->normalized )
9558  return SCIP_OKAY;
9559 
9560  capacity = consdata->capacity;
9561 
9562  /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9563 
9564  SCIP_CALL( normalizeCumulativeCondition(scip, consdata->nvars, consdata->vars, consdata->durations,
9565  consdata->demands, &consdata->capacity, nchgcoefs, nchgsides) );
9566 
9567  consdata->normalized = TRUE;
9568 
9569  if( capacity > consdata->capacity )
9570  consdata->varbounds = FALSE;
9571 
9572  return SCIP_OKAY;
9573 }
9574 
9575 /** computes for the given cumulative condition the effective horizon */
9576 static
9578  SCIP* scip, /**< SCIP data structure */
9579  int nvars, /**< number of variables (jobs) */
9580  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9581  int* durations, /**< array containing corresponding durations */
9582  int* demands, /**< array containing corresponding demands */
9583  int capacity, /**< available cumulative capacity */
9584  int* hmin, /**< pointer to store the left bound of the effective horizon */
9585  int* hmax, /**< pointer to store the right bound of the effective horizon */
9586  int* split /**< point were the cumulative condition can be split */
9587  )
9588 {
9589  SCIP_PROFILE* profile;
9590 
9591  /* create empty resource profile with infinity resource capacity */
9592  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9593 
9594  /* create worst case resource profile */
9595  SCIP_CALL( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands) );
9596 
9597  /* print resource profile in if SCIP_DEBUG is defined */
9598  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
9599 
9600  /* computes the first time point where the resource capacity can be violated */
9601  (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9602 
9603  /* computes the first time point where the resource capacity is satisfied for sure */
9604  (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9605 
9606  (*split) = (*hmax);
9607 
9608  if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9609  {
9610  int* timepoints;
9611  int* loads;
9612  int ntimepoints;
9613  int t;
9614 
9615  /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9616  * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9617  * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9618  * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9619  * explain the certain "old" bound changes
9620  */
9621 
9622  /* search for time points */
9623  ntimepoints = SCIPprofileGetNTimepoints(profile);
9624  timepoints = SCIPprofileGetTimepoints(profile);
9625  loads = SCIPprofileGetLoads(profile);
9626 
9627  /* 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 */
9628  for( t = 0; t < ntimepoints; ++t )
9629  {
9630  /* ignore all time points before the effective horizon */
9631  if( timepoints[t] <= *hmin )
9632  continue;
9633 
9634  /* ignore all time points after the effective horizon */
9635  if( timepoints[t] >= *hmax )
9636  break;
9637 
9638  /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9639  * can split the cumulative constraint into two cumulative constraints
9640  */
9641  if( loads[t] <= capacity )
9642  {
9643  (*split) = timepoints[t];
9644  break;
9645  }
9646  }
9647  }
9648 
9649  /* free worst case profile */
9650  SCIPprofileFree(&profile);
9651 
9652  return SCIP_OKAY;
9653 }
9654 
9655 /** creates and adds a cumulative constraint */
9656 static
9658  SCIP* scip, /**< SCIP data structure */
9659  const char* name, /**< name of constraint */
9660  int nvars, /**< number of variables (jobs) */
9661  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9662  int* durations, /**< array containing corresponding durations */
9663  int* demands, /**< array containing corresponding demands */
9664  int capacity, /**< available cumulative capacity */
9665  int hmin, /**< left bound of time axis to be considered (including hmin) */
9666  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9667  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9668  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9669  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9670  * Usually set to TRUE. */
9671  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9672  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9673  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9674  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9675  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9676  * Usually set to TRUE. */
9677  SCIP_Bool local, /**< is constraint only valid locally?
9678  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9679  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9680  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9681  * adds coefficients to this constraint. */
9682  SCIP_Bool dynamic, /**< is constraint subject to aging?
9683  * Usually set to FALSE. Set to TRUE for own cuts which
9684  * are seperated as constraints. */
9685  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9686  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9687  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9688  * if it may be moved to a more global node?
9689  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9690  )
9691 {
9692  SCIP_CONS* cons;
9693 
9694  /* creates cumulative constraint and adds it to problem */
9695  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9696  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9697 
9698  /* adjust the effective time horizon of the new constraint */
9699  SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9700  SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9701 
9702  /* add and release new cumulative constraint */
9703  SCIP_CALL( SCIPaddCons(scip, cons) );
9704  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9705 
9706  return SCIP_OKAY;
9707 }
9708 
9709 /** computes the effective horizon and checks if the constraint can be decompsed */
9710 static
9712  SCIP* scip, /**< SCIP data structure */
9713  SCIP_CONS* cons, /**< cumulative constraint */
9714  int* ndelconss, /**< pointer to store the number of deleted constraints */
9715  int* naddconss, /**< pointer to store the number of added constraints */
9716  int* nchgsides /**< pointer to store the number of changed sides */
9717  )
9718 {
9719  SCIP_CONSDATA* consdata;
9720  int hmin;
9721  int hmax;
9722  int split;
9723 
9724  consdata = SCIPconsGetData(cons);
9725  assert(consdata != NULL);
9726 
9727  if( consdata->nvars <= 1 )
9728  return SCIP_OKAY;
9729 
9730  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9731  consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9732 
9733  /* check if this time point improves the effective horizon */
9734  if( consdata->hmin < hmin )
9735  {
9736  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9737 
9738  consdata->hmin = hmin;
9739  (*nchgsides)++;
9740  }
9741 
9742  /* check if this time point improves the effective horizon */
9743  if( consdata->hmax > hmax )
9744  {
9745  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9746  consdata->hmax = hmax;
9747  (*nchgsides)++;
9748  }
9749 
9750  /* check if the constraint is redundant */
9751  if( consdata->hmax <= consdata->hmin )
9752  {
9753  SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9754  SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9755 
9756  SCIP_CALL( SCIPdelCons(scip, cons) );
9757  (*ndelconss)++;
9758  }
9759  else if( consdata->hmin < split && split < consdata->hmax )
9760  {
9761  char name[SCIP_MAXSTRLEN];
9762  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9763 
9764  SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9765  SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9766 
9767  assert(split < consdata->hmax);
9768 
9769  /* creates cumulative constraint and adds it to problem */
9770  SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9771  consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9774 
9775  /* adjust the effective time horizon of the constraint */
9776  consdata->hmax = split;
9777 
9778  assert(consdata->hmin < consdata->hmax);
9779 
9780  /* for the statistic we count the number of time we decompose a cumulative constraint */
9782  (*naddconss)++;
9783  }
9784 
9785  return SCIP_OKAY;
9786 }
9787 
9788 
9789 /** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9790  *
9791  * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9792  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9793  *
9794  * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9795  * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9796  * down-lock of the corresponding start time variable can be removed.
9797  *
9798  * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9799  * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9800  * negative, than the job can be dual fixed to its earlier start time (est).
9801  *
9802  * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9803  * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9804  * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9805  *
9806  * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9807  * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9808  * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9809  * form variable domain is dual feasible.
9810  *
9811  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9812  * the cumulative condition; The deletion has to be done later.
9813  */
9814 static
9816  SCIP* scip, /**< SCIP data structure */
9817  int nvars, /**< number of start time variables (activities) */
9818  SCIP_VAR** vars, /**< array of start time variables */
9819  int* durations, /**< array of durations */
9820  int hmin, /**< left bound of time axis to be considered (including hmin) */
9821  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9822  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9823  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9824  SCIP_CONS* cons, /**< underlying constraint, or NULL */
9825  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9826  int* nfixedvars, /**< pointer to store the number of fixed variables */
9827  int* nchgsides, /**< pointer to store the number of changed sides */
9828  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9829  )
9830 {
9831  SCIP_Real* downimpllbs;
9832  SCIP_Real* downimplubs;
9833  SCIP_Real* downproplbs;
9834  SCIP_Real* downpropubs;
9835  SCIP_Real* upimpllbs;
9836  SCIP_Real* upimplubs;
9837  SCIP_Real* upproplbs;
9838  SCIP_Real* uppropubs;
9839 
9840  int firstminect;
9841  int secondminect;
9842  int v;
9843 
9844  /* get temporary memory for storing probing results needed for step (4) and (5) */
9845  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9846  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9847  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9848  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9849  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9850  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9851  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9852  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9853 
9854  assert(scip != NULL);
9855  assert(nvars > 1);
9856  assert(cons != NULL);
9857 
9858  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9859 
9860  firstminect = INT_MAX;
9861  secondminect = INT_MAX;
9862 
9863  /* compute the two smallest earlier completion times; which are needed for step (5) */
9864  for( v = 0; v < nvars; ++v )
9865  {
9866  int ect;
9867 
9868  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9869 
9870  if( ect < firstminect )
9871  {
9872  secondminect = firstminect;
9873  firstminect = ect;
9874  }
9875  else if( ect < secondminect )
9876  secondminect = ect;
9877  }
9878 
9879  /* loop over all jobs and check if one of the 5 reductions can be applied */
9880  for( v = 0; v < nvars; ++v )
9881  {
9882  SCIP_VAR* var;
9883  int duration;
9884 
9885  int alternativelb;
9886  int minect;
9887  int est;
9888  int ect;
9889  int lst;
9890  int lct;
9891 
9892  var = vars[v];
9893  assert(var != NULL);
9894 
9895  duration = durations[v];
9896  assert(duration > 0);
9897 
9898  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
9899  * time (lct)
9900  */
9901  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9902  ect = est + duration;
9903  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9904  lct = lst + duration;
9905 
9906  /* compute the earliest completion time of all remaining jobs */
9907  if( ect == firstminect )
9908  minect = secondminect;
9909  else
9910  minect = firstminect;
9911 
9912  /* compute potential alternative lower bound (step (4) and (5)) */
9913  alternativelb = MAX(hmin+1, minect);
9914  alternativelb = MIN(alternativelb, hmax);
9915 
9916  if( lct <= hmin )
9917  {
9918  /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
9919  * cumulative condition
9920  */
9921  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
9922  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
9923 
9924  /* mark variable to be irrelevant */
9925  irrelevants[v] = TRUE;
9926 
9927  /* for the statistic we count the number of jobs which are irrelevant */
9928  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9929  }
9930  else if( lst <= hmin && SCIPconsIsChecked(cons) )
9931  {
9932  /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
9933  * so the down lock can be omitted
9934  */
9935 
9936  assert(downlocks != NULL);
9937  assert(uplocks != NULL);
9938 
9939  if( !uplocks[v] )
9940  {
9941  /* the variables has no up lock and we can also remove the down lock;
9942  * => lst <= hmin and ect >= hmax
9943  * => remove job and reduce capacity by the demand of that job
9944  *
9945  * We mark the job to be deletable. The removement together with the capacity reducion is done later
9946  */
9947 
9948  SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
9949  SCIPvarGetName(var), ect - duration, lst, duration);
9950 
9951  /* mark variable to be irrelevant */
9952  irrelevants[v] = TRUE;
9953 
9954  /* for the statistic we count the number of jobs which always run during the effective horizon */
9956  }
9957 
9958  if( downlocks[v] )
9959  {
9960  SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
9961  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
9962 
9963  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
9964  downlocks[v] = FALSE;
9965  (*nchgsides)++;
9966 
9967  /* for the statistic we count the number of removed locks */
9969  }
9970  }
9971  else if( ect <= hmin )
9972  {
9973  /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
9974  * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
9975  * removed form the cumulative condition after it was fixed to its earliest start time
9976  */
9977 
9978  /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
9979  * bound;
9980  */
9981  if( downlocks != NULL && SCIPconsIsChecked(cons) )
9982  {
9983  /* fix integer start time variable if possible to it lower bound */
9984  SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
9985  }
9986 
9987  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
9988  {
9989  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
9990  SCIPvarGetName(var), ect - duration, lst, duration);
9991 
9992  /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
9993  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
9994 
9995  /* mark variable to be irrelevant */
9996  irrelevants[v] = TRUE;
9997 
9998  /* for the statistic we count the number of jobs which are dual fixed */
10000  }
10001  }
10002  else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10003  {
10004  assert(downlocks != NULL);
10005 
10006  /* check step (4) and (5) */
10007 
10008  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10009  * is in favor of rounding the variable down
10010  */
10011  if( SCIPvarGetNLocksDown(var) == (int)(downlocks[v]) )
10012  {
10013  SCIP_Bool roundable;
10014 
10015  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10016 
10017  if( roundable )
10018  {
10019  if( alternativelb > lst )
10020  {
10021  SCIP_Bool infeasible;
10022  SCIP_Bool fixed;
10023 
10024  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10025  assert(!infeasible);
10026  assert(fixed);
10027 
10028  (*nfixedvars)++;
10029 
10030  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10031  * constraints
10032  */
10034  }
10035  else
10036  {
10037  SCIP_Bool success;
10038 
10039  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10040  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10041  * infeasible we can apply the dual reduction; otherwise we do nothing
10042  */
10043  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10044  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10045  nfixedvars, &success, cutoff) );
10046 
10047  if( success )
10048  {
10050  }
10051  }
10052  }
10053  }
10054  }
10055 
10056  SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10057  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10058  }
10059 
10060  /* free temporary memory */
10061  SCIPfreeBufferArray(scip, &uppropubs);
10062  SCIPfreeBufferArray(scip, &upproplbs);
10063  SCIPfreeBufferArray(scip, &upimplubs);
10064  SCIPfreeBufferArray(scip, &upimpllbs);
10065  SCIPfreeBufferArray(scip, &downpropubs);
10066  SCIPfreeBufferArray(scip, &downproplbs);
10067  SCIPfreeBufferArray(scip, &downimplubs);
10068  SCIPfreeBufferArray(scip, &downimpllbs);
10069 
10070  return SCIP_OKAY;
10071 }
10072 
10073 /** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10074  *
10075  * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10076  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10077  *
10078  * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10079  * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10080  * up-lock of the corresponding start time variable can be removed.
10081  *
10082  * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10083  * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10084  * positive, than the job can be dual fixed to its latest start time (lst).
10085  *
10086  * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10087  * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10088  * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10089  * of the corresponding job).
10090 
10091  * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10092  * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10093  * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10094  * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10095  *
10096  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10097  * the cumulative condition; The deletion has to be done later.
10098  */
10099 static
10101  SCIP* scip, /**< SCIP data structure */
10102  int nvars, /**< number of start time variables (activities) */
10103  SCIP_VAR** vars, /**< array of start time variables */
10104  int* durations, /**< array of durations */
10105  int hmin, /**< left bound of time axis to be considered (including hmin) */
10106  int hmax, /**< right bound of time axis to be considered (not including hmax) */
10107  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10108  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10109  SCIP_CONS* cons, /**< underlying constraint, or NULL */
10110  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10111  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10112  int* nchgsides, /**< pointer to store the number of changed sides */
10113  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10114  )
10115 {
10116  SCIP_Real* downimpllbs;
10117  SCIP_Real* downimplubs;
10118  SCIP_Real* downproplbs;
10119  SCIP_Real* downpropubs;
10120  SCIP_Real* upimpllbs;
10121  SCIP_Real* upimplubs;
10122  SCIP_Real* upproplbs;
10123  SCIP_Real* uppropubs;
10124 
10125  int firstmaxlst;
10126  int secondmaxlst;
10127  int v;
10128 
10129  /* get temporary memory for storing probing results needed for step (4) and (5) */
10130  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10131  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10132  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10133  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10134  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10135  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10136  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10137  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10138 
10139  assert(scip != NULL);
10140  assert(nvars > 1);
10141  assert(cons != NULL);
10142 
10143  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10144 
10145  firstmaxlst = INT_MIN;
10146  secondmaxlst = INT_MIN;
10147 
10148  /* compute the two largest latest start times; which are needed for step (5) */
10149  for( v = 0; v < nvars; ++v )
10150  {
10151  int lst;
10152 
10153  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(vars[v]));
10154 
10155  if( lst > firstmaxlst )
10156  {
10157  secondmaxlst = firstmaxlst;
10158  firstmaxlst = lst;
10159  }
10160  else if( lst > secondmaxlst )
10161  secondmaxlst = lst;
10162  }
10163 
10164  /* loop over all jobs and check if one of the 5 reductions can be applied */
10165  for( v = 0; v < nvars; ++v )
10166  {
10167  SCIP_VAR* var;
10168  int duration;
10169 
10170  int alternativeub;
10171  int maxlst;
10172  int est;
10173  int ect;
10174  int lst;
10175 
10176  var = vars[v];
10177  assert(var != NULL);
10178 
10179  duration = durations[v];
10180  assert(duration > 0);
10181 
10182  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10183  * time (lct)
10184  */
10185  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10186  ect = est + duration;
10187  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10188 
10189  /* compute the latest start time of all remaining jobs */
10190  if( lst == firstmaxlst )
10191  maxlst = secondmaxlst;
10192  else
10193  maxlst = firstmaxlst;
10194 
10195  /* compute potential alternative upper bound (step (4) and (5)) */
10196  alternativeub = MIN(hmax - 1, maxlst) - duration;
10197  alternativeub = MAX(alternativeub, hmin);
10198 
10199  if( est >= hmax )
10200  {
10201  /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10202  * cumulative condition
10203  */
10204  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10205  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10206 
10207  /* mark variable to be irrelevant */
10208  irrelevants[v] = TRUE;
10209 
10210  /* for the statistic we count the number of jobs which are irrelevant */
10211  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10212  }
10213  else if( ect >= hmax && SCIPconsIsChecked(cons) )
10214  {
10215  assert(downlocks != NULL);
10216  assert(uplocks != NULL);
10217 
10218  /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10219  * so the up lock can be omitted
10220  */
10221 
10222  if( !downlocks[v] )
10223  {
10224  /* the variables has no down lock and we can also remove the up lock;
10225  * => lst <= hmin and ect >= hmax
10226  * => remove job and reduce capacity by the demand of that job
10227  */
10228  SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10229  SCIPvarGetName(var), est, lst, duration);
10230 
10231  /* mark variable to be irrelevant */
10232  irrelevants[v] = TRUE;
10233 
10234  /* for the statistic we count the number of jobs which always run during the effective horizon */
10236  }
10237 
10238  if( uplocks[v] )
10239  {
10240  SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10241  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10242 
10243  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10244  uplocks[v] = FALSE;
10245  (*nchgsides)++;
10246 
10247  /* for the statistic we count the number of removed locks */
10249  }
10250  }
10251  else if( lst >= hmax )
10252  {
10253  /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10254  * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10255  * removed form the cumulative condition after it was fixed to its latest start time
10256  */
10257 
10258  /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10259  * bound
10260  */
10261  if( uplocks != NULL && SCIPconsIsChecked(cons) )
10262  {
10263  /* fix integer start time variable if possible to its upper bound */
10264  SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10265  }
10266 
10267  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10268  {
10269  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10270  SCIPvarGetName(var), est, lst, duration);
10271 
10272  /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10273  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10274 
10275  /* mark variable to be irrelevant */
10276  irrelevants[v] = TRUE;
10277 
10278  /* for the statistic we count the number of jobs which are dual fixed */
10280  }
10281  }
10282  else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10283  {
10284  assert(uplocks != NULL);
10285 
10286  /* check step (4) and (5) */
10287 
10288  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10289  * is in favor of rounding the variable down
10290  */
10291  if( SCIPvarGetNLocksUp(var) == (int)(uplocks[v]) )
10292  {
10293  SCIP_Bool roundable;
10294 
10295  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10296 
10297  if( roundable )
10298  {
10299  if( alternativeub < est )
10300  {
10301  SCIP_Bool infeasible;
10302  SCIP_Bool fixed;
10303 
10304  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10305  assert(!infeasible);
10306  assert(fixed);
10307 
10308  (*nfixedvars)++;
10309 
10310  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10311  * constraints
10312  */
10314  }
10315  else
10316  {
10317  SCIP_Bool success;
10318 
10319  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10320  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10321  * in infeasible we can apply the dual reduction; otherwise we do nothing
10322  */
10323  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10324  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10325  nfixedvars, &success, cutoff) );
10326 
10327  if( success )
10328  {
10330  }
10331  }
10332  }
10333  }
10334  }
10335  }
10336 
10337  /* free temporary memory */
10338  SCIPfreeBufferArray(scip, &uppropubs);
10339  SCIPfreeBufferArray(scip, &upproplbs);
10340  SCIPfreeBufferArray(scip, &upimplubs);
10341  SCIPfreeBufferArray(scip, &upimpllbs);
10342  SCIPfreeBufferArray(scip, &downpropubs);
10343  SCIPfreeBufferArray(scip, &downproplbs);
10344  SCIPfreeBufferArray(scip, &downimplubs);
10345  SCIPfreeBufferArray(scip, &downimpllbs);
10346 
10347  return SCIP_OKAY;
10348 }
10349 
10350 /** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10351 static
10353  SCIP* scip, /**< SCIP data structure */
10354  SCIP_CONS* cons, /**< cumulative constraint */
10355  int* nfixedvars, /**< pointer to store the number of fixed variables */
10356  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10357  int* nchgsides, /**< pointer to store the number of changed sides */
10358  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10359  )
10360 {
10361  SCIP_CONSDATA* consdata;
10362  SCIP_Bool* irrelevants;
10363  int nvars;
10364  int v;
10365 
10366  assert(scip != NULL);
10367  assert(cons != NULL);
10368  assert(!(*cutoff));
10369 
10370  consdata = SCIPconsGetData(cons);
10371  assert(consdata != NULL);
10372 
10373  nvars = consdata->nvars;
10374 
10375  if( nvars <= 1 )
10376  return SCIP_OKAY;
10377 
10378  SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10379  BMSclearMemoryArray(irrelevants, nvars);
10380 
10381  /* presolve constraint form the earlier start time point of view */
10382  SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10383  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10384  irrelevants, nfixedvars, nchgsides, cutoff) );
10385 
10386  /* presolve constraint form the latest completion time point of view */
10387  SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10388  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10389  irrelevants, nfixedvars, nchgsides, cutoff) );
10390 
10391  /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10392  * order to ensure a correct behaviour
10393  */
10394  for( v = nvars-1; v >= 0; --v )
10395  {
10396  if( irrelevants[v] )
10397  {
10398  SCIP_VAR* var;
10399  int ect;
10400  int lst;
10401 
10402  var = consdata->vars[v];
10403  assert(var != NULL);
10404 
10405  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10406  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10407 
10408  /* check if the jobs runs completely during the effective horizon */
10409  if( lst <= consdata->hmin && ect >= consdata->hmax )
10410  {
10411  if( consdata->capacity < consdata->demands[v] )
10412  {
10413  *cutoff = TRUE;
10414  break;
10415  }
10416 
10417  consdata->capacity -= consdata->demands[v];
10418  consdata->varbounds = FALSE;
10419  }
10420 
10421  SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10422  (*nchgcoefs)++;
10423  }
10424  }
10425 
10426  SCIPfreeBufferArray(scip, &irrelevants);
10427 
10428  return SCIP_OKAY;
10429 }
10430 
10431 /** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10432 static
10434  SCIP* scip, /**< SCIP data structure */
10435  SCIP_CONSDATA* consdata, /**< constraint data */
10436  int* startindices, /**< permutation with rspect to the start times */
10437  int curtime, /**< current point in time */
10438  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10439  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10440  SCIP_Longint** demands, /**< pointer to array storing the demands */
10441  int* ndemands /**< pointer to store the number of different demands */
10442  )
10443 {
10444  int startindex;
10445  int ncountedvars;
10446 
10447  assert(demands != NULL);
10448  assert(ndemands != NULL);
10449 
10450  ncountedvars = 0;
10451  startindex = nstarted - 1;
10452 
10453  *ndemands = 0;
10454 
10455  /* search for the (nstarted - nfinished) jobs which are active at curtime */
10456  while( nstarted - nfinished > ncountedvars )
10457  {
10458  SCIP_VAR* var;
10459  int endtime;
10460  int varidx;
10461 
10462  /* collect job information */
10463  varidx = startindices[startindex];
10464  assert(varidx >= 0 && varidx < consdata->nvars);
10465 
10466  var = consdata->vars[varidx];
10467  assert(var != NULL);
10468 
10469  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10470 
10471  /* check the end time of this job is larger than the curtime; in this case the job is still running */
10472  if( endtime > curtime )
10473  {
10474  if( consdata->demands[varidx] < consdata->capacity )
10475  {
10476  (*demands)[*ndemands] = consdata->demands[varidx];
10477  (*ndemands)++;
10478  }
10479  ncountedvars++;
10480  }
10481 
10482  startindex--;
10483  }
10484 
10485  return SCIP_OKAY;
10486 }
10487 
10488 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10489  * constraint
10490  */
10491 static
10493  SCIP* scip, /**< SCIP data structure */
10494  SCIP_CONS* cons, /**< constraint to be checked */
10495  int* startindices, /**< permutation with rspect to the start times */
10496  int curtime, /**< current point in time */
10497  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10498  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10499  int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10500  )
10501 {
10502  SCIP_CONSDATA* consdata;
10503  SCIP_Longint* demands;
10504  SCIP_Real* profits;
10505  int* items;
10506  int ndemands;
10507  SCIP_Bool success;
10508  SCIP_Real solval;
10509  int j;
10510  assert(nstarted > nfinished);
10511 
10512  consdata = SCIPconsGetData(cons);
10513  assert(consdata != NULL);
10514  assert(consdata->nvars > 0);
10515  assert(consdata->capacity > 0);
10516 
10517  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10518  ndemands = 0;
10519 
10520  /* get demand array to initialize knapsack problem */
10521  SCIP_CALL( collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands) );
10522 
10523  /* create array for profits */
10524  SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10525  SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10526  for( j = 0; j < ndemands; ++j )
10527  {
10528  profits[j] = (SCIP_Real) demands[j];
10529  items[j] = j;/* this is only a dummy value*/
10530  }
10531 
10532  /* solve knapsack problem and get maximum capacity usage <= capacity */
10533  SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10534  items, NULL, NULL, NULL, NULL, &solval, &success) );
10535 
10536  assert(SCIPisFeasIntegral(scip, solval));
10537 
10538  /* store result */
10539  *bestcapacity = SCIPconvertRealToInt(scip, solval);
10540 
10541  SCIPfreeBufferArray(scip, &items);
10542  SCIPfreeBufferArray(scip, &profits);
10543  SCIPfreeBufferArray(scip, &demands);
10544 
10545  return SCIP_OKAY;
10546 }
10547 
10548 /** try to tighten the capacity
10549  * -- using DP for knapsack, we find the maximum possible capacity usage
10550  * -- neglects hmin and hmax, such that it is also able to check solutions globally
10551  */
10552 static
10554  SCIP* scip, /**< SCIP data structure */
10555  SCIP_CONS* cons, /**< cumulative constraint */
10556  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10557  int* nchgsides /**< pointer to store the number of changed sides */
10558  )
10559 {
10560  SCIP_CONSDATA* consdata;
10561  int* starttimes; /* stores when each job is starting */
10562  int* endtimes; /* stores when each job ends */
10563  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10564  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10565 
10566  int nvars; /* number of activities for this constraint */
10567  int freecapacity; /* remaining capacity */
10568  int curtime; /* point in time which we are just checking */
10569  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10570 
10571  int bestcapacity;
10572 
10573  int j;
10574 
10575  assert(scip != NULL);
10576  assert(cons != NULL);
10577  assert(nchgsides != NULL);
10578 
10579  consdata = SCIPconsGetData(cons);
10580  assert(consdata != NULL);
10581 
10582  nvars = consdata->nvars;
10583 
10584  /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10585  if( nvars <= 1 || consdata->capacity <= 1 )
10586  return SCIP_OKAY;
10587 
10588  assert(consdata->vars != NULL);
10589 
10590  SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10591  SCIPconsGetName(cons), consdata->capacity);
10592 
10593  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10594  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10595  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10596  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10597 
10598  /* create event point arrays */
10599  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10600  starttimes, endtimes, startindices, endindices, FALSE);
10601 
10602  bestcapacity = 1;
10603  endindex = 0;
10604  freecapacity = consdata->capacity;
10605 
10606  /* check each startpoint of a job whether the capacity is kept or not */
10607  for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10608  {
10609  curtime = starttimes[j];
10610  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10611 
10612  /* remove the capacity requirments for all job which start at the curtime */
10613  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10614 
10615  /* add the capacity requirments for all job which end at the curtime */
10616  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10617 
10618  assert(freecapacity <= consdata->capacity);
10619  assert(endindex <= nvars);
10620 
10621  /* endindex - points to the next job which will finish */
10622  /* j - points to the last job that has been released */
10623 
10624  /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10625  if( freecapacity < 0 )
10626  {
10627  int newcapacity;
10628 
10629  newcapacity = 1;
10630 
10631  /* get best possible upper bound on capacity usage */
10632  SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10633 
10634  /* update bestcapacity */
10635  bestcapacity = MAX(bestcapacity, newcapacity);
10636  SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10637  }
10638 
10639  /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10640  if( freecapacity > 0 && freecapacity != consdata->capacity )
10641  {
10642  bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10643  SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10644  }
10645 
10646  /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10647  if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10648  {
10649  /* if demands[startindices[j]] == cap then exactly that job is running */
10650  SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10651  bestcapacity = consdata->capacity;
10652  break;
10653  }
10654  } /*lint --e{850}*/
10655 
10656  /* free all buffer arrays */
10657  SCIPfreeBufferArray(scip, &endindices);
10658  SCIPfreeBufferArray(scip, &startindices);
10659  SCIPfreeBufferArray(scip, &endtimes);
10660  SCIPfreeBufferArray(scip, &starttimes);
10661 
10662  /* check whether capacity can be tightened and whether demands need to be adjusted */
10663  if( bestcapacity < consdata->capacity )
10664  {
10665  int oldnchgcoefs;
10666 
10667  SCIPdebug(oldnchgcoefs = *nchgcoefs; )
10668 
10669  SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10670  SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10671 
10672  for( j = 0; j < nvars; ++j )
10673  {
10674  if( consdata->demands[j] == consdata->capacity )
10675  {
10676  consdata->demands[j] = bestcapacity;
10677  (*nchgcoefs)++;
10678  }
10679  }
10680 
10681  consdata->capacity = bestcapacity;
10682  (*nchgsides)++;
10683 
10684  SCIPdebugMsgPrint(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs);
10685 
10686  consdata->varbounds = FALSE;
10687  }
10688 
10689  return SCIP_OKAY;
10690 }
10691 
10692 /** tries to change coefficients:
10693  * demand_j < cap && all other parallel jobs in conflict
10694  * ==> set demand_j := cap
10695  */
10696 static
10698  SCIP* scip, /**< SCIP data structure */
10699  SCIP_CONS* cons, /**< cumulative constraint */
10700  int* nchgcoefs /**< pointer to count total number of changed coefficients */
10701  )
10702 {
10703  SCIP_CONSDATA* consdata;
10704  int nvars;
10705  int j;
10706  int oldnchgcoefs;
10707  int mindemand;
10708 
10709  assert(scip != NULL);
10710  assert(cons != NULL);
10711  assert(nchgcoefs != NULL);
10712 
10713  /* get constraint data for some parameter testings only! */
10714  consdata = SCIPconsGetData(cons);
10715  assert(consdata != NULL);
10716 
10717  nvars = consdata->nvars;
10718  oldnchgcoefs = *nchgcoefs;
10719 
10720  if( nvars <= 0 )
10721  return SCIP_OKAY;
10722 
10723  /* PRE1:
10724  * check all jobs j whether: r_j + r_min > capacity holds
10725  * if so: adjust r_j to capacity
10726  */
10727  mindemand = consdata->demands[0];
10728  for( j = 0; j < nvars; ++j )
10729  {
10730  mindemand = MIN(mindemand, consdata->demands[j]);
10731  }
10732 
10733  /*check each job */
10734  for( j = 0; j < nvars; ++j )
10735  {
10736  if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10737  {
10738  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10739  consdata->demands[j], consdata->capacity);
10740  consdata->demands[j] = consdata->capacity;
10741  (*nchgcoefs)++;
10742  }
10743  }
10744 
10745  /* PRE2:
10746  * check for each job (with d_j < cap)
10747  * whether it is disjunctive to all others over the time horizon
10748  */
10749  for( j = 0; j < nvars; ++j )
10750  {
10751  SCIP_Bool chgcoef;
10752  int est_j;
10753  int lct_j;
10754  int i;
10755 
10756  assert(consdata->demands[j] <= consdata->capacity);
10757 
10758  if( consdata->demands[j] == consdata->capacity )
10759  continue;
10760 
10761  chgcoef = TRUE;
10762 
10763  est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10764  lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10765 
10766  for( i = 0; i < nvars; ++i )
10767  {
10768  int est_i;
10769  int lct_i;
10770 
10771  if( i == j )
10772  continue;
10773 
10774  est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10775  lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10776 
10777  if( est_i >= lct_j || est_j >= lct_i )
10778  continue;
10779 
10780  if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10781  {
10782  chgcoef = FALSE;
10783  break;
10784  }
10785  }
10786 
10787  if( chgcoef )
10788  {
10789  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10790  consdata->demands[j], consdata->capacity);
10791  consdata->demands[j] = consdata->capacity;
10792  (*nchgcoefs)++;
10793  }
10794 
10795  }
10796 
10797  if( (*nchgcoefs) > oldnchgcoefs )
10798  {
10799  SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10800  (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10801  }
10802 
10803  return SCIP_OKAY;
10804 }
10805 
10806 #if 0
10807 /** try to reformulate constraint by replacing certain jobs */
10808 static
10809 SCIP_RETCODE reformulateCons(
10810  SCIP* scip, /**< SCIP data structure */
10811  SCIP_CONS* cons, /**< cumulative constraint */
10812  int* naggrvars /**< pointer to store the number of aggregated variables */
10813  )
10814 {
10815  SCIP_CONSDATA* consdata;
10816  int hmin;
10817  int hmax;
10818  int nvars;
10819  int v;
10820 
10821  consdata = SCIPconsGetData(cons);
10822  assert(cons != NULL);
10823 
10824  nvars = consdata->nvars;
10825  assert(nvars > 1);
10826 
10827  hmin = consdata->hmin;
10828  hmax = consdata->hmax;
10829  assert(hmin < hmax);
10830 
10831  for( v = 0; v < nvars; ++v )
10832  {
10833  SCIP_VAR* var;
10834  int duration;
10835  int est;
10836  int ect;
10837  int lst;
10838  int lct;
10839 
10840  var = consdata->vars[v];
10841  assert(var != NULL);
10842 
10843  duration = consdata->durations[v];
10844 
10845  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10846  ect = est + duration;
10847  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10848  lct = lst + duration;
10849 
10850  /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10851  assert(lst > hmin || ect < hmax);
10852 
10853  if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10854  {
10855  SCIP_VAR* aggrvar;
10856  char name[SCIP_MAXSTRLEN];
10857  SCIP_Bool infeasible;
10858  SCIP_Bool redundant;
10859  SCIP_Bool aggregated;
10860  int shift;
10861 
10862  shift = est - (hmin - lct + MIN(hmin, ect));
10863  assert(shift > 0);
10864  lst = hmin;
10865  duration = hmin - lct;
10866 
10867  SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10868  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10869 
10870  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10871  SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10873  SCIP_CALL( SCIPaddVar(scip, var) );
10874  SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10875 
10876  assert(!infeasible);
10877  assert(!redundant);
10878  assert(aggregated);
10879 
10880  /* replace variable */
10881  consdata->durations[v] = duration;
10882  consdata->vars[v] = aggrvar;
10883 
10884  /* remove and add locks */
10885  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10886  SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10887 
10888  SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10889 
10890  (*naggrvars)++;
10891  }
10892  }
10893 
10894  return SCIP_OKAY;
10895 }
10896 #endif
10897 
10898 /** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10899 static
10901  SCIP* scip, /**< SCIP data structure */
10902  SCIP_CONS* cons, /**< cumulative constraint */
10903  int* naddconss /**< pointer to store the number of added constraints */
10904  )
10905 {
10906  SCIP_CONSDATA* consdata;
10907  SCIP_VAR** vars;
10908  int* durations;
10909  int* demands;
10910  int capacity;
10911  int halfcapacity;
10912  int mindemand;
10913  int nvars;
10914  int v;
10915 
10916  consdata = SCIPconsGetData(cons);
10917  assert(consdata != NULL);
10918 
10919  capacity = consdata->capacity;
10920 
10921  if( capacity == 1 )
10922  return SCIP_OKAY;
10923 
10924  SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
10925  SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
10926  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10927 
10928  halfcapacity = capacity / 2;
10929  mindemand = consdata->capacity;
10930  nvars = 0;
10931 
10932  /* collect all jobs with demand larger than half of the capacity */
10933  for( v = 0; v < consdata->nvars; ++v )
10934  {
10935  if( consdata->demands[v] > halfcapacity )
10936  {
10937  vars[nvars] = consdata->vars[v];
10938  demands[nvars] = 1;
10939  durations[nvars] = consdata->durations[v];
10940  nvars++;
10941 
10942  mindemand = MIN(mindemand, consdata->demands[v]);
10943  }
10944  }
10945 
10946  if( nvars > 0 )
10947  {
10948  /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
10949  * job is still to large to be scheduled in parallel
10950  */
10951  for( v = 0; v < consdata->nvars; ++v )
10952  {
10953  if( consdata->demands[v] > halfcapacity )
10954  continue;
10955 
10956  if( mindemand + consdata->demands[v] > capacity )
10957  {
10958  demands[nvars] = 1;
10959  durations[nvars] = consdata->durations[v];
10960  vars[nvars] = consdata->vars[v];
10961  nvars++;
10962 
10963  /* @todo create one cumulative constraint and look for another small demand */
10964  break;
10965  }
10966  }
10967 
10968  /* creates cumulative constraint and adds it to problem */
10969  SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
10971  (*naddconss)++;
10972  }
10973 
10974  SCIPfreeBufferArray(scip, &demands);
10975  SCIPfreeBufferArray(scip, &durations);
10976  SCIPfreeBufferArray(scip, &vars);
10977 
10978  return SCIP_OKAY;
10979 }
10980 
10981 /** presolve given constraint */
10982 static
10984  SCIP* scip, /**< SCIP data structure */
10985  SCIP_CONS* cons, /**< cumulative constraint */
10986  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
10987  SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
10988  int* nfixedvars, /**< pointer to store the number of fixed variables */
10989 #if 0
10990  int* naggrvars, /**< pointer to counter which is increased by the number of deduced variable aggregations */
10991 #endif
10992  int* nchgbds, /**< pointer to store the number of changed bounds */
10993  int* ndelconss, /**< pointer to store the number of deleted constraints */
10994  int* naddconss, /**< pointer to store the number of added constraints */
10995  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10996  int* nchgsides, /**< pointer to store the number of changed sides */
10997  SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
10998  SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
10999  )
11000 {
11001  assert(!SCIPconsIsDeleted(cons));
11002 
11003  /* only perform dual reductions on model constraints */
11004  if( conshdlrdata->dualpresolve && SCIPallowDualReds(scip) )
11005  {
11006  /* computes the effective horizon and checks if the constraint can be decomposed */
11007  SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11008 
11009  if( SCIPconsIsDeleted(cons) )
11010  return SCIP_OKAY;
11011 
11012  /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11013  * fixings (dual reductions)
11014  */
11015  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11016  {
11017  SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11018 
11019  if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11020  return SCIP_OKAY;
11021  }
11022 
11023  SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11024 
11025  if( *cutoff || SCIPconsIsDeleted(cons) )
11026  return SCIP_OKAY;
11027  }
11028 
11029  /* remove jobs which have a demand larger than the capacity */
11030  SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11031  assert((*cutoff) || checkDemands(scip, cons));
11032 
11033  if( *cutoff )
11034  return SCIP_OKAY;
11035 
11036  if( conshdlrdata->normalize )
11037  {
11038  /* divide demands by their greatest common divisor */
11039  SCIP_CALL( normalizeDemands(scip, cons, nchgcoefs, nchgsides) );
11040  }
11041 
11042  /* delete constraint with one job */
11043  SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11044 
11045  if( *cutoff || SCIPconsIsDeleted(cons) )
11046  return SCIP_OKAY;
11047 
11048  if( conshdlrdata->coeftightening )
11049  {
11050  /* try to tighten the capacity */
11051  SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11052 
11053  /* try to tighten the coefficients */
11054  SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11055  }
11056 
11057  assert(checkDemands(scip, cons) || *cutoff);
11058 
11059 #if 0
11060  SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11061 #endif
11062 
11063  return SCIP_OKAY;
11064 }
11065 
11066 /**@name TClique Graph callbacks
11067  *
11068  * @{
11069  */
11070 
11071 /** tclique graph data */
11072 struct TCLIQUE_Graph
11073 {
11074  SCIP_VAR** vars; /**< start time variables each of them is a node */
11075  SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11076  SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11077  SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11078  TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11079  int* ninarcs; /**< number if in arcs for the precedence graph */
11080  int* noutarcs; /**< number if out arcs for the precedence graph */
11081  int* durations; /**< for each node the duration of the corresponding job */
11082  int nnodes; /**< number of nodes */
11083  int size; /**< size of the array */
11084 };
11085 
11086 /** gets number of nodes in the graph */
11087 static
11088 TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11090  assert(tcliquegraph != NULL);
11091 
11092  return tcliquegraph->nnodes;
11093 }
11094 
11095 /** gets weight of nodes in the graph */
11096 static
11097 TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11099  assert(tcliquegraph != NULL);
11100 
11101  return tcliquegraph->weights;
11102 }
11103 
11104 /** returns, whether the edge (node1, node2) is in the graph */
11105 static
11106 TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11108  assert(tcliquegraph != NULL);
11109  assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11110  assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11111 
11112  /* check if an arc exits in the precedence graph */
11113  if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11114  return TRUE;
11115 
11116  /* check if an edge exits in the non-overlapping graph */
11117  if( tcliquegraph->demandmatrix[node1][node2] )
11118  return TRUE;
11119 
11120  return FALSE;
11121 }
11122 
11123 /** selects all nodes from a given set of nodes which are adjacent to a given node
11124  * and returns the number of selected nodes
11125  */
11126 static
11127 TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11129  int nadjnodes;
11130  int i;
11131 
11132  assert(tcliquegraph != NULL);
11133  assert(0 <= node && node < tcliquegraph->nnodes);
11134  assert(nnodes == 0 || nodes != NULL);
11135  assert(adjnodes != NULL);
11136 
11137  nadjnodes = 0;
11138 
11139  for( i = 0; i < nnodes; i++ )
11140  {
11141  /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11142  assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11143  assert(i == 0 || nodes[i-1] < nodes[i]);
11144 
11145  /* check if an edge exists */
11146  if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11147  {
11148  /* current node is adjacent to given node */
11149  adjnodes[nadjnodes] = nodes[i];
11150  nadjnodes++;
11151  }
11152  }
11153 
11154  return nadjnodes;
11155 }
11156 
11157 /** generates cuts using a clique found by algorithm for maximum weight clique
11158  * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11159  */
11160 static
11161 TCLIQUE_NEWSOL(tcliqueNewsolClique)
11162 { /*lint --e{715}*/
11163  SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11164 }
11165 
11166 /** print the tclique graph */
11167 #if 0
11168 static
11169 void tcliquePrint(
11170  SCIP* scip, /**< SCIP data structure */
11171  TCLIQUE_GRAPH* tcliquegraph /**< tclique graph */
11172  )
11173 {
11174  int nnodes;
11175  int i;
11176  int j;
11177 
11178  nnodes = tcliquegraph->nnodes;
11179 
11180  for( i = 0; i < nnodes; ++i )
11181  {
11182  for( j = 0; j < nnodes; ++j )
11183  {
11184  SCIPinfoMessage(scip, NULL, "(%d/%d) ", tcliquegraph->precedencematrix[i][j], tcliquegraph->demandmatrix[i][j]);
11185  }
11186  SCIPinfoMessage(scip, NULL, "\n");
11187  }
11188 }
11189 #endif
11190 
11191 /** @} */
11192 
11193 /** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11194  * job corresponding to variable bound variable (vlbvar)
11195  *
11196  * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11197  */
11198 static
11200  SCIP* scip, /**< SCIP data structure */
11201  SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11202  SCIP_Real vlbcoef, /**< variable bound coefficient */
11203  SCIP_Real vlbconst, /**< variable bound constant */
11204  int duration /**< duration of the variable bound variable */
11205  )
11206 {
11207  if( SCIPisEQ(scip, vlbcoef, 1.0) )
11208  {
11209  if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11210  {
11211  /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11212  return TRUE;
11213  }
11214  }
11215  else
11216  {
11217  SCIP_Real bound;
11218 
11219  bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11220 
11221  if( SCIPisLT(scip, vlbcoef, 1.0) )
11222  {
11223  SCIP_Real ub;
11224 
11225  ub = SCIPvarGetUbLocal(vlbvar);
11226 
11227  /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11228  if( SCIPisLE(scip, ub, bound) )
11229  return TRUE;
11230  }
11231  else
11232  {
11233  SCIP_Real lb;
11234 
11235  assert(SCIPisGT(scip, vlbcoef, 1.0));
11236 
11237  lb = SCIPvarGetLbLocal(vlbvar);
11238 
11239  /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11240  if( SCIPisGE(scip, lb, bound) )
11241  return TRUE;
11242  }
11243  }
11244 
11245  return FALSE;
11246 }
11247 
11248 /** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11249  * job corresponding to variable which is bounded (var)
11250  *
11251  * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11252  */
11253 static
11255  SCIP* scip, /**< SCIP data structure */
11256  SCIP_VAR* var, /**< variable which is bound from above */
11257  SCIP_Real vubcoef, /**< variable bound coefficient */
11258  SCIP_Real vubconst, /**< variable bound constant */
11259  int duration /**< duration of the variable which is bounded from above */
11260  )
11261 {
11262  SCIP_Real vlbcoef;
11263  SCIP_Real vlbconst;
11264 
11265  /* convert the variable upper bound into an variable lower bound */
11266  vlbcoef = 1.0 / vubcoef;
11267  vlbconst = -vubconst / vubcoef;
11268 
11269  return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11270 }
11271 
11272 /** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11273  * others an index larger than the number if active variables
11274  */
11275 static
11277  SCIP* scip, /**< SCIP data structure */
11278  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11279  SCIP_VAR* var, /**< variable for which we want the index */
11280  int* idx /**< pointer to store the index */
11281  )
11282 {
11283  (*idx) = SCIPvarGetProbindex(var);
11284 
11285  if( (*idx) == -1 )
11286  {
11287  if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11288  {
11289  (*idx) = (int)(size_t) SCIPhashmapGetImage(tcliquegraph->varmap, (void*)var);
11290  }
11291  else
11292  {
11293  int pos;
11294  int v;
11295 
11296  /**@todo we might want to add the aggregation path to graph */
11297 
11298  /* check if we have to realloc memory */
11299  if( tcliquegraph->size == tcliquegraph->nnodes )
11300  {
11301  int size;
11302 
11303  size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11304  tcliquegraph->size = size;
11305 
11306  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11307  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11308  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11309  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11310  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11311 
11312  for( v = 0; v < tcliquegraph->nnodes; ++v )
11313  {
11314  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11315  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11316  }
11317  }
11318  assert(tcliquegraph->nnodes < tcliquegraph->size);
11319 
11320  pos = tcliquegraph->nnodes;
11321  assert(pos >= 0);
11322 
11323  tcliquegraph->durations[pos] = 0;
11324  tcliquegraph->weights[pos] = 0;
11325  tcliquegraph->vars[pos] = var;
11326 
11327  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11328  BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11329 
11330  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11331  BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11332 
11333  SCIP_CALL( SCIPhashmapInsert(tcliquegraph->varmap, (void*)var, (void*)(size_t)(pos)) );
11334 
11335  tcliquegraph->nnodes++;
11336 
11337  for( v = 0; v < tcliquegraph->nnodes; ++v )
11338  {
11339  tcliquegraph->precedencematrix[v][pos] = 0;
11340  tcliquegraph->demandmatrix[v][pos] = 0;
11341  }
11342 
11343  (*idx) = tcliquegraph->nnodes;
11344  }
11345  }
11346  else
11347  {
11348  assert(*idx == (int)(size_t)SCIPhashmapGetImage(tcliquegraph->varmap, (void*)var));
11349  }
11350 
11351  assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11352 
11353  return SCIP_OKAY;
11354 }
11355 
11356 /** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11357  *
11358  * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11359  * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11360  *
11361  * (i) b = 1 and c >= d
11362  * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11363  * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11364  *
11365  */
11366 static
11368  SCIP* scip, /**< SCIP data structure */
11369  TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11370  )
11371 {
11372  SCIP_VAR** vars;
11373  int nvars;
11374  int v;
11375 
11376  vars = SCIPgetVars(scip);
11377  nvars = SCIPgetNVars(scip);
11378 
11379  /* try to project each arc of the variable bound graph to precedence condition */
11380  for( v = 0; v < nvars; ++v )
11381  {
11382  SCIP_VAR** vbdvars;
11383  SCIP_VAR* var;
11384  SCIP_Real* vbdcoefs;
11385  SCIP_Real* vbdconsts;
11386  int nvbdvars;
11387  int idx1;
11388  int b;
11389 
11390  var = vars[v];
11391  assert(var != NULL);
11392 
11393  SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11394  assert(idx1 >= 0);
11395 
11396  if( tcliquegraph->durations[idx1] == 0 )
11397  continue;
11398 
11399  vbdvars = SCIPvarGetVlbVars(var);
11400  vbdcoefs = SCIPvarGetVlbCoefs(var);
11401  vbdconsts = SCIPvarGetVlbConstants(var);
11402  nvbdvars = SCIPvarGetNVlbs(var);
11403 
11404  for( b = 0; b < nvbdvars; ++b )
11405  {
11406  int idx2;
11407 
11408  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11409  assert(idx2 >= 0);
11410 
11411  if( tcliquegraph->durations[idx2] == 0 )
11412  continue;
11413 
11414  if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11415  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11416  }
11417 
11418  vbdvars = SCIPvarGetVubVars(var);
11419  vbdcoefs = SCIPvarGetVubCoefs(var);
11420  vbdconsts = SCIPvarGetVubConstants(var);
11421  nvbdvars = SCIPvarGetNVubs(var);
11422 
11423  for( b = 0; b < nvbdvars; ++b )
11424  {
11425  int idx2;
11426 
11427  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11428  assert(idx2 >= 0);
11429 
11430  if( tcliquegraph->durations[idx2] == 0 )
11431  continue;
11432 
11433  if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11434  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11435  }
11436 
11437  for( b = v+1; b < nvars; ++b )
11438  {
11439  int idx2;
11440 
11441  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11442  assert(idx2 >= 0);
11443 
11444  if( tcliquegraph->durations[idx2] == 0 )
11445  continue;
11446 
11447  /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11448  if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11449  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11450 
11451  /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11452  if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11453  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11454  }
11455  }
11456 
11457  return SCIP_OKAY;
11458 }
11459 
11460 /** compute the transitive closer of the given graph and the number of in and out arcs */
11461 static
11462 void transitiveClosure(
11463  SCIP_Bool** adjmatrix, /**< adjacent matrix */
11464  int* ninarcs, /**< array to store the number of in arcs */
11465  int* noutarcs, /**< array to store the number of out arcs */
11466  int nnodes /**< number if nodes */
11467  )
11468 {
11469  int i;
11470  int j;
11471  int k;
11472 
11473  for( i = 0; i < nnodes; ++i )
11474  {
11475  for( j = 0; j < nnodes; ++j )
11476  {
11477  if( adjmatrix[i][j] )
11478  {
11479  ninarcs[j]++;
11480  noutarcs[i]++;
11481 
11482  for( k = 0; k < nnodes; ++k )
11483  {
11484  if( adjmatrix[j][k] )
11485  adjmatrix[i][k] = TRUE;
11486  }
11487  }
11488  }
11489  }
11490 }
11491 
11492 /** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11493 static
11495  SCIP* scip, /**< SCIP data structure */
11496  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11497  SCIP_CONS** conss, /**< array of cumulative constraints */
11498  int nconss /**< number of cumulative constraints */
11499  )
11500 {
11501  int c;
11502 
11503  /* use the cumulative constraints to initialize the none overlapping graph */
11504  for( c = 0; c < nconss; ++c )
11505  {
11506  SCIP_CONSDATA* consdata;
11507  SCIP_VAR** vars;
11508  int* demands;
11509  int capacity;
11510  int nvars;
11511  int i;
11512 
11513  consdata = SCIPconsGetData(conss[c]);
11514  assert(consdata != NULL);
11515 
11516  vars = consdata->vars;
11517  demands = consdata->demands;
11518 
11519  nvars = consdata->nvars;
11520  capacity = consdata->capacity;
11521 
11522  SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11523 
11524  /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11525  for( i = 0; i < nvars; ++i )
11526  {
11527  int idx1;
11528  int j;
11529 
11530  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11531  assert(idx1 >= 0);
11532 
11533  if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11534  continue;
11535 
11536  for( j = i+1; j < nvars; ++j )
11537  {
11538  assert(consdata->durations[j] > 0);
11539 
11540  if( demands[i] + demands[j] > capacity )
11541  {
11542  int idx2;
11543  int est1;
11544  int est2;
11545  int lct1;
11546  int lct2;
11547 
11548  /* check if the effective horizon is large enough */
11549  est1 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[i]));
11550  est2 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[j]));
11551 
11552  /* at least one of the jobs needs to start at hmin or later */
11553  if( est1 < consdata->hmin && est2 < consdata->hmin )
11554  continue;
11555 
11556  lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11557  lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11558 
11559  /* at least one of the jobs needs to finish not later then hmin */
11560  if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11561  continue;
11562 
11563  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11564  assert(idx2 >= 0);
11565  assert(idx1 != idx2);
11566 
11567  if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11568  continue;
11569 
11570  SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11571 
11572  assert(tcliquegraph->durations[idx1] > 0);
11573  assert(tcliquegraph->durations[idx2] > 0);
11574 
11575  tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11576  tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11577 
11578  }
11579  }
11580  }
11581  }
11582 
11583  return SCIP_OKAY;
11584 }
11585 
11586 /** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11587  * of jobs cannot run in parallel
11588  */
11589 static
11591  SCIP* scip, /**< SCIP data structure */
11592  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11593  SCIP_CONS** conss, /**< array of cumulative constraints */
11594  int nconss /**< number of cumulative constraints */
11595  )
11596 {
11597  assert(scip != NULL);
11598  assert(tcliquegraph != NULL);
11599 
11600  /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11601  SCIP_CALL( projectVbd(scip, tcliquegraph) );
11602 
11603  /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11604  transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11605 
11606  /* constraints non-overlapping graph */
11607  SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11608 
11609  return SCIP_OKAY;
11610 }
11611 
11612 /** create cumulative constraint from conflict set */
11613 static
11615  SCIP* scip, /**< SCIP data structure */
11616  const char* name, /**< constraint name */
11617  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11618  int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11619  int ncliquenodes /**< number of nodes in the clique */
11620  )
11621 {
11622  SCIP_CONS* cons;
11623  SCIP_VAR** vars;
11624  int* durations;
11625  int* demands;
11626  int v;
11627 
11628  SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11629  SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11630  SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11631 
11632  SCIPsortInt(cliquenodes, ncliquenodes);
11633 
11634  /* collect variables, durations, and demands */
11635  for( v = 0; v < ncliquenodes; ++v )
11636  {
11637  durations[v] = tcliquegraph->durations[cliquenodes[v]];
11638  assert(durations[v] > 0);
11639  demands[v] = 1;
11640  vars[v] = tcliquegraph->vars[cliquenodes[v]];
11641  }
11642 
11643  /* create (unary) cumulative constraint */
11644  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11646 
11647  SCIP_CALL( SCIPaddCons(scip, cons) );
11648  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11649 
11650  /* free buffers */
11651  SCIPfreeBufferArray(scip, &demands);
11652  SCIPfreeBufferArray(scip, &durations);
11653  SCIPfreeBufferArray(scip, &vars);
11654 
11655  return SCIP_OKAY;
11656 }
11657 
11658 /** search for cumulative constrainst */
11659 static
11661  SCIP* scip, /**< SCIP data structure */
11662  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11663  int* naddconss /**< pointer to store the number of added constraints */
11664  )
11665 {
11666  TCLIQUE_STATUS tcliquestatus;
11667  SCIP_Bool* precedencerow;
11668  SCIP_Bool* precedencecol;
11669  SCIP_Bool* demandrow;
11670  SCIP_Bool* demandcol;
11671  SCIP_HASHTABLE* covered;
11672  int* cliquenodes;
11673  int ncliquenodes;
11674  int cliqueweight;
11675  int ntreenodes;
11676  int nnodes;
11677  int nconss;
11678  int v;
11679 
11680  nnodes = tcliquegraph->nnodes;
11681  nconss = 0;
11682 
11683  /* initialize the weight of each job with its duration */
11684  for( v = 0; v < nnodes; ++v )
11685  {
11686  tcliquegraph->weights[v] = tcliquegraph->durations[v];
11687  }
11688 
11689  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11690  SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11691  SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11692  SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11693  SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11694 
11695  /* create a hash table to store all start time variables which are already covered by at least one clique */
11696  SCIP_CALL( SCIPhashtableCreate(&covered, SCIPblkmem(scip), nnodes,
11697  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11698 
11699  /* for each variables/job we are ... */
11700  for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11701  {
11702  char name[SCIP_MAXSTRLEN];
11703  int c;
11704 
11705  /* jobs with zero durations are skipped */
11706  if( tcliquegraph->durations[v] == 0 )
11707  continue;
11708 
11709  /* check if the start time variable is already covered by at least one clique */
11710  if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11711  continue;
11712 
11713  SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11714 
11715  /* temporarily remove the connection via the precedence graph */
11716  for( c = 0; c < nnodes; ++c )
11717  {
11718  precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11719  precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11720 
11721  demandrow[c] = tcliquegraph->demandmatrix[v][c];
11722  demandcol[c] = tcliquegraph->demandmatrix[c][v];
11723 
11724 #if 0
11725  if( precedencerow[c] || precedencecol[c] )
11726  {
11727  tcliquegraph->demandmatrix[v][c] = FALSE;
11728  tcliquegraph->demandmatrix[c][v] = FALSE;
11729  }
11730 #endif
11731 
11732  tcliquegraph->precedencematrix[c][v] = FALSE;
11733  tcliquegraph->precedencematrix[v][c] = FALSE;
11734  }
11735 
11736  /* find (heuristically) maximum cliques which includes node v */
11737  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11738  tcliquegraph, tcliqueNewsolClique, NULL,
11739  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11740  10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11741 
11742  SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11743 
11744  if( ncliquenodes == 1 )
11745  continue;
11746 
11747  /* construct constraint name */
11748  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11749 
11750  SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11751  nconss++;
11752 
11753  /* all start time variable to covered hash table */
11754  for( c = 0; c < ncliquenodes; ++c )
11755  {
11756  SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11757  }
11758 
11759  /* copy the precedence relations back */
11760  for( c = 0; c < nnodes; ++c )
11761  {
11762  tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11763  tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11764 
11765  tcliquegraph->demandmatrix[v][c] = demandrow[c];
11766  tcliquegraph->demandmatrix[c][v] = demandcol[c];
11767  }
11768  }
11769 
11770  SCIPhashtableFree(&covered);
11771 
11772  SCIPfreeBufferArray(scip, &demandcol);
11773  SCIPfreeBufferArray(scip, &demandrow);
11774  SCIPfreeBufferArray(scip, &precedencecol);
11775  SCIPfreeBufferArray(scip, &precedencerow);
11776  SCIPfreeBufferArray(scip, &cliquenodes);
11777 
11778  (*naddconss) += nconss;
11779 
11780  /* for the statistic we count the number added disjunctive constraints */
11781  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11782 
11783  return SCIP_OKAY;
11784 }
11785 
11786 /** create precedence constraint (as variable bound constraint */
11787 static
11789  SCIP* scip, /**< SCIP data structure */
11790  const char* name, /**< constraint name */
11791  SCIP_VAR* var, /**< variable x that has variable bound */
11792  SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11793  int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11794  )
11795 {
11796  SCIP_CONS* cons;
11797 
11798  /* create variable bound constraint */
11799  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11801 
11802  SCIPdebugPrintCons(scip, cons, NULL);
11803 
11804  /* add constraint to problem and release it */
11805  SCIP_CALL( SCIPaddCons(scip, cons) );
11806  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11807 
11808  return SCIP_OKAY;
11809 }
11810 
11811 /** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11812 static
11814  SCIP* scip, /**< SCIP data structure */
11815  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11816  int source, /**< index of the source node */
11817  int sink, /**< index of the sink node */
11818  int* naddconss /**< pointer to store the number of added constraints */
11819  )
11820 {
11821  TCLIQUE_WEIGHT cliqueweight;
11822  TCLIQUE_STATUS tcliquestatus;
11823  SCIP_VAR** vars;
11824  int* cliquenodes;
11825  int nnodes;
11826  int lct;
11827  int est;
11828  int i;
11829 
11830  int ntreenodes;
11831  int ncliquenodes;
11832 
11833  /* check if source and sink are connencted */
11834  if( !tcliquegraph->precedencematrix[source][sink] )
11835  return SCIP_OKAY;
11836 
11837  nnodes = tcliquegraph->nnodes;
11838  vars = tcliquegraph->vars;
11839 
11840  /* reset the weights to zero */
11841  BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11842 
11843  /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11844  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11845  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[sink]));
11846 
11847  /* weight all jobs which run for sure between source and sink with their duration */
11848  for( i = 0; i < nnodes; ++i )
11849  {
11850  SCIP_VAR* var;
11851  int duration;
11852 
11853  var = vars[i];
11854  assert(var != NULL);
11855 
11856  duration = tcliquegraph->durations[i];
11857 
11858  if( i == source || i == sink )
11859  {
11860  /* source and sink are not weighted */
11861  tcliquegraph->weights[i] = 0;
11862  }
11863  else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11864  {
11865  /* job i runs after source and before sink */
11866  tcliquegraph->weights[i] = duration;
11867  }
11868  else if( lct <= SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var))
11869  && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11870  {
11871  /* job i run in between due the bounds of the start time variables */
11872  tcliquegraph->weights[i] = duration;
11873  }
11874  else
11875  tcliquegraph->weights[i] = 0;
11876  }
11877 
11878  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11879 
11880  /* find (heuristically) maximum cliques */
11881  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11882  tcliquegraph, tcliqueNewsolClique, NULL,
11883  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11884  10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11885 
11886  if( ncliquenodes > 1 )
11887  {
11888  char name[SCIP_MAXSTRLEN];
11889  int distance;
11890 
11891  /* construct constraint name */
11892  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11893 
11894  /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11895  * duration of the source job
11896  */
11897  distance = cliqueweight + tcliquegraph->durations[source];
11898 
11899  SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11900  (*naddconss)++;
11901  }
11902 
11903  SCIPfreeBufferArray(scip, &cliquenodes);
11904 
11905  return SCIP_OKAY;
11906 }
11907 
11908 /** search for precedence constraints
11909  *
11910  * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
11911  * corresponding two jobs
11912  */
11913 static
11915  SCIP* scip, /**< SCIP data structure */
11916  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11917  int* naddconss /**< pointer to store the number of added constraints */
11918  )
11919 {
11920  int* sources;
11921  int* sinks;
11922  int nconss;
11923  int nnodes;
11924  int nsources;
11925  int nsinks;
11926  int i;
11927 
11928  nnodes = tcliquegraph->nnodes;
11929  nconss = 0;
11930 
11931  nsources = 0;
11932  nsinks = 0;
11933 
11934  SCIP_CALL( SCIPallocBufferArray(scip, &sources, nnodes) );
11935  SCIP_CALL( SCIPallocBufferArray(scip, &sinks, nnodes) );
11936 
11937  /* first collect all sources and sinks */
11938  for( i = 0; i < nnodes; ++i )
11939  {
11940  if( tcliquegraph->ninarcs[i] == 0 )
11941  {
11942  sources[nsources] = i;
11943  nsources++;
11944  }
11945 
11946  if( tcliquegraph->ninarcs[i] == 0 )
11947  {
11948  sinks[nsinks] = i;
11949  nsinks++;
11950  }
11951  }
11952 
11953  /* compute for each node a minimum distance to each sources and each sink */
11954  for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
11955  {
11956  int j;
11957 
11958  for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
11959  {
11960  SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
11961  }
11962 
11963  for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
11964  {
11965  SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
11966  }
11967  }
11968 
11969  (*naddconss) += nconss;
11970 
11971  /* for the statistic we count the number added variable constraints */
11972  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
11973 
11974  SCIPfreeBufferArray(scip, &sinks);
11975  SCIPfreeBufferArray(scip, &sources);
11976 
11977  return SCIP_OKAY;
11978 }
11979 
11980 /** initialize the assumed durations for each variable */
11981 static
11983  SCIP* scip, /**< SCIP data structure */
11984  TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
11985  SCIP_CONS** conss, /**< cumulative constraints */
11986  int nconss /**< number of cumulative constraints */
11987  )
11988 {
11989  int c;
11990 
11991  /* use the cumulative structure to define the duration we are using for each job */
11992  for( c = 0; c < nconss; ++c )
11993  {
11994  SCIP_CONSDATA* consdata;
11995  SCIP_VAR** vars;
11996  int nvars;
11997  int v;
11998 
11999  consdata = SCIPconsGetData(conss[c]);
12000  assert(consdata != NULL);
12001 
12002  vars = consdata->vars;
12003  nvars = consdata->nvars;
12004 
12005  for( v = 0; v < nvars; ++v )
12006  {
12007  int idx;
12008 
12009  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12010  assert(idx >= 0);
12011 
12012  /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12013  * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12014  * general this is not the case. Therefore, the question would be which duration should be used?
12015  */
12016  tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12017  assert(tcliquegraph->durations[idx] > 0);
12018  }
12019  }
12020 
12021  return SCIP_OKAY;
12022 }
12023 
12024 /** create tclique graph */
12025 static
12027  SCIP* scip, /**< SCIP data structure */
12028  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12029  )
12030 {
12031  SCIP_VAR** vars;
12032  SCIP_HASHMAP* varmap;
12033  SCIP_Bool** precedencematrix;
12034  SCIP_Bool** demandmatrix;
12035  int* ninarcs;
12036  int* noutarcs;
12037  int* durations;
12038  int* weights;
12039  int nvars;
12040  int v;
12041 
12042  vars = SCIPgetVars(scip);
12043  nvars = SCIPgetNVars(scip);
12044 
12045  /* allocate memory for the tclique graph data structure */
12046  SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12047 
12048  /* create the variable mapping hash map */
12049  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
12050 
12051  /* each active variables get a node in the graph */
12052  SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12053 
12054  /* allocate memory for the projected variables bound graph and the none overlapping graph */
12055  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12056  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12057 
12058  /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12059  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12060  BMSclearMemoryArray(weights, nvars);
12061 
12062  /* array to store the number of in arc of the precedence graph */
12063  SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12064  BMSclearMemoryArray(ninarcs, nvars);
12065 
12066  /* array to store the number of out arc of the precedence graph */
12067  SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12068  BMSclearMemoryArray(noutarcs, nvars);
12069 
12070  /* array to store the used duration for each node */
12071  SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12072  BMSclearMemoryArray(durations, nvars);
12073 
12074  for( v = 0; v < nvars; ++v )
12075  {
12076  SCIP_VAR* var;
12077 
12078  var = vars[v];
12079  assert(var != NULL);
12080 
12081  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12082  BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12083 
12084  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12085  BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12086 
12087  /* insert all active variables into the garph */
12088  assert(SCIPvarGetProbindex(var) == v);
12089  SCIP_CALL( SCIPhashmapInsert(varmap, (void*)var, (void*)(size_t)v) ); /*lint !e571*/
12090  }
12091 
12092  (*tcliquegraph)->nnodes = nvars;
12093  (*tcliquegraph)->varmap = varmap;
12094  (*tcliquegraph)->precedencematrix = precedencematrix;
12095  (*tcliquegraph)->demandmatrix = demandmatrix;
12096  (*tcliquegraph)->weights = weights;
12097  (*tcliquegraph)->ninarcs = ninarcs;
12098  (*tcliquegraph)->noutarcs = noutarcs;
12099  (*tcliquegraph)->durations = durations;
12100  (*tcliquegraph)->size = nvars;
12101 
12102  return SCIP_OKAY;
12103 }
12104 
12105 /** frees the tclique graph */
12106 static
12107 void freeTcliqueGraph(
12108  SCIP* scip, /**< SCIP data structure */
12109  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12110  )
12111 {
12112  int v;
12113 
12114  for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12115  {
12116  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12117  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12118  }
12119 
12120  SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12121  SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12122  SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12123  SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12124  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12125  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12126  SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12127  SCIPhashmapFree(&(*tcliquegraph)->varmap);
12128 
12129  SCIPfreeBuffer(scip, tcliquegraph);
12130 }
12131 
12132 /** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12133  * constrains (disjunctive constraint)
12134  */
12135 static
12137  SCIP* scip, /**< SCIP data structure */
12138  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12139  SCIP_CONS** conss, /**< array of cumulative constraints */
12140  int nconss, /**< number of cumulative constraints */
12141  int* naddconss /**< pointer to store the number of added constraints */
12142  )
12143 {
12144  TCLIQUE_GRAPH* tcliquegraph;
12145 
12146  /* create tclique graph */
12147  SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12148 
12149  /* define for each job a duration */
12150  SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12151 
12152  /* constuct incompatibility graph */
12153  SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12154 
12155  /* search for new precedence constraints */
12156  if( conshdlrdata->detectvarbounds )
12157  {
12158  SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12159  }
12160 
12161  /* search for new cumulative constraints */
12162  if( conshdlrdata->detectdisjunctive )
12163  {
12164  SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12165  }
12166 
12167  /* free tclique graph data structure */
12168  freeTcliqueGraph(scip, &tcliquegraph);
12169 
12170  return SCIP_OKAY;
12171 }
12172 
12173 /** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12174 static
12176  SCIP_CONSDATA* consdata /**< cumulative constraint data */
12177  )
12178 {
12179  SCIP_VAR** vars;
12180  int nvars;
12181  int v;
12182 
12183  if( consdata->validsignature )
12184  return;
12185 
12186  vars = consdata->vars;
12187  nvars = consdata->nvars;
12188 
12189  for( v = 0; v < nvars; ++v )
12190  {
12191  consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12192  }
12193 
12194  consdata->validsignature = TRUE;
12195 }
12196 
12197 /** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12198 static
12199 SCIP_DECL_SORTINDCOMP(consdataCompVar)
12200 { /*lint --e{715}*/
12201  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12202 
12203  assert(consdata != NULL);
12204  assert(0 <= ind1 && ind1 < consdata->nvars);
12205  assert(0 <= ind2 && ind2 < consdata->nvars);
12206 
12207  return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12208 }
12209 
12210 /** run a pairwise comparison */
12211 static
12213  SCIP* scip, /**< SCIP data structure */
12214  SCIP_CONS** conss, /**< array of cumulative constraints */
12215  int nconss, /**< number of cumulative constraints */
12216  int* ndelconss /**< pointer to store the number of deletedconstraints */
12217  )
12218 {
12219  int i;
12220  int j;
12221 
12222  for( i = 0; i < nconss; ++i )
12223  {
12224  SCIP_CONSDATA* consdata0;
12225  SCIP_CONS* cons0;
12226 
12227  cons0 = conss[i];
12228  assert(cons0 != NULL);
12229 
12230  consdata0 = SCIPconsGetData(cons0);
12231  assert(consdata0 != NULL);
12232 
12233  consdataCalcSignature(consdata0);
12234  assert(consdata0->validsignature);
12235 
12236  for( j = i+1; j < nconss; ++j )
12237  {
12238  SCIP_CONSDATA* consdata1;
12239  SCIP_CONS* cons1;
12240 
12241  cons1 = conss[j];
12242  assert(cons1 != NULL);
12243 
12244  consdata1 = SCIPconsGetData(cons1);
12245  assert(consdata1 != NULL);
12246 
12247  if( consdata0->capacity != consdata1->capacity )
12248  continue;
12249 
12250  consdataCalcSignature(consdata1);
12251  assert(consdata1->validsignature);
12252 
12253  if( (consdata1->signature & (~consdata0->signature)) == 0 )
12254  {
12255  SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12256  SCIPswapPointers((void**)&cons0, (void**)&cons1);
12257  assert((consdata0->signature & (~consdata1->signature)) == 0);
12258  }
12259 
12260  if( (consdata0->signature & (~consdata1->signature)) == 0 )
12261  {
12262  int* perm0;
12263  int* perm1;
12264  int v0;
12265  int v1;
12266 
12267  if( consdata0->nvars > consdata1->nvars )
12268  continue;
12269 
12270  if( consdata0->hmin < consdata1->hmin )
12271  continue;
12272 
12273  if( consdata0->hmax > consdata1->hmax )
12274  continue;
12275 
12276  SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12277  SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12278 
12279  /* call sorting method */
12280  SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12281  SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12282 
12283  for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12284  {
12285  SCIP_VAR* var0;
12286  SCIP_VAR* var1;
12287  int idx0;
12288  int idx1;
12289  int comp;
12290 
12291  idx0 = perm0[v0];
12292  idx1 = perm1[v1];
12293 
12294  var0 = consdata0->vars[idx0];
12295 
12296  var1 = consdata1->vars[idx1];
12297 
12298  comp = SCIPvarCompare(var0, var1);
12299 
12300  if( comp == 0 )
12301  {
12302  int duration0;
12303  int duration1;
12304  int demand0;
12305  int demand1;
12306 
12307  demand0 = consdata0->demands[idx0];
12308  duration0 = consdata0->durations[idx0];
12309 
12310  demand1 = consdata1->demands[idx1];
12311  duration1 = consdata1->durations[idx1];
12312 
12313  if( demand0 != demand1 )
12314  break;
12315 
12316  if( duration0 != duration1 )
12317  break;
12318 
12319  v0++;
12320  v1++;
12321  }
12322  else if( comp > 0 )
12323  v1++;
12324  else
12325  break;
12326  }
12327 
12328  if( v0 == consdata0->nvars )
12329  {
12330  if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12331  {
12332  initializeLocks(consdata1, TRUE);
12333  }
12334 
12335  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12336 
12337  SCIP_CALL( SCIPdelCons(scip, cons0) );
12338  (*ndelconss)++;
12339  }
12340 
12341  SCIPfreeBufferArray(scip, &perm1);
12342  SCIPfreeBufferArray(scip, &perm0);
12343  }
12344  }
12345  }
12346 
12347  return SCIP_OKAY;
12348 }
12349 
12350 /** strengthen the variable bounds using the cumulative condition */
12351 static
12353  SCIP* scip, /**< SCIP data structure */
12354  SCIP_CONS* cons, /**< constraint to propagate */
12355  int* nchgbds, /**< pointer to store the number of changed bounds */
12356  int* naddconss /**< pointer to store the number of added constraints */
12357  )
12358 {
12359  SCIP_CONSDATA* consdata;
12360  SCIP_VAR** vars;
12361  int* durations;
12362  int* demands;
12363  int capacity;
12364  int nvars;
12365  int nconss;
12366  int i;
12367 
12368  consdata = SCIPconsGetData(cons);
12369  assert(consdata != NULL);
12370 
12371  /* check if the variable bounds got already strengthen by the cumulative constraint */
12372  if( consdata->varbounds )
12373  return SCIP_OKAY;
12374 
12375  vars = consdata->vars;
12376  durations = consdata->durations;
12377  demands = consdata->demands;
12378  capacity = consdata->capacity;
12379  nvars = consdata->nvars;
12380 
12381  nconss = 0;
12382 
12383  for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12384  {
12385  SCIP_VAR** vbdvars;
12386  SCIP_VAR* var;
12387  SCIP_Real* vbdcoefs;
12388  SCIP_Real* vbdconsts;
12389  int nvbdvars;
12390  int b;
12391  int j;
12392 
12393  var = consdata->vars[i];
12394  assert(var != NULL);
12395 
12396  vbdvars = SCIPvarGetVlbVars(var);
12397  vbdcoefs = SCIPvarGetVlbCoefs(var);
12398  vbdconsts = SCIPvarGetVlbConstants(var);
12399  nvbdvars = SCIPvarGetNVlbs(var);
12400 
12401  for( b = 0; b < nvbdvars; ++b )
12402  {
12403  if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12404  {
12405  if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12406  {
12407  for( j = 0; j < nvars; ++j )
12408  {
12409  if( vars[j] == vbdvars[b] )
12410  break;
12411  }
12412  if( j == nvars )
12413  continue;
12414 
12415  if( demands[i] + demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12416  {
12417  SCIP_Bool infeasible;
12418  char name[SCIP_MAXSTRLEN];
12419  int nlocalbdchgs;
12420 
12421  SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12422 
12423  /* construct constraint name */
12424  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12425 
12426  SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12427  nconss++;
12428 
12429  SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12430  assert(!infeasible);
12431 
12432  (*nchgbds) += nlocalbdchgs;
12433  }
12434  }
12435  }
12436  }
12437  }
12438 
12439  (*naddconss) += nconss;
12440 
12441  consdata->varbounds = TRUE;
12442 
12443  return SCIP_OKAY;
12444 }
12445 
12446 /** helper function to enforce constraints */
12447 static
12449  SCIP* scip, /**< SCIP data structure */
12450  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
12451  SCIP_CONS** conss, /**< constraints to process */
12452  int nconss, /**< number of constraints */
12453  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
12454  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
12455  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
12456  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
12457  )
12458 {
12459  SCIP_CONSHDLRDATA* conshdlrdata;
12460 
12461  assert(conshdlr != NULL);
12462  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12463  assert(nconss == 0 || conss != NULL);
12464  assert(result != NULL);
12465 
12466  if( solinfeasible )
12467  {
12468  *result = SCIP_INFEASIBLE;
12469  return SCIP_OKAY;
12470  }
12471 
12472  SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12473  sol == NULL ? "LP" : "relaxation");
12474 
12475  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12476  assert(conshdlrdata != NULL);
12477 
12478  (*result) = SCIP_FEASIBLE;
12479 
12480  if( conshdlrdata->usebinvars )
12481  {
12482  SCIP_Bool separated;
12483  SCIP_Bool cutoff;
12484  int c;
12485 
12486  separated = FALSE;
12487 
12488  /* first check if a constraints is violated */
12489  for( c = 0; c < nusefulconss; ++c )
12490  {
12491  SCIP_CONS* cons;
12492  SCIP_Bool violated;
12493 
12494  cons = conss[c];
12495  assert(cons != NULL);
12496 
12497  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12498 
12499  if( !violated )
12500  continue;
12501 
12502  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12503  if ( cutoff )
12504  {
12505  *result = SCIP_CUTOFF;
12506  return SCIP_OKAY;
12507  }
12508  }
12509 
12510  for( ; c < nconss && !separated; ++c )
12511  {
12512  SCIP_CONS* cons;
12513  SCIP_Bool violated;
12514 
12515  cons = conss[c];
12516  assert(cons != NULL);
12517 
12518  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12519 
12520  if( !violated )
12521  continue;
12522 
12523  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12524  if ( cutoff )
12525  {
12526  *result = SCIP_CUTOFF;
12527  return SCIP_OKAY;
12528  }
12529  }
12530 
12531  if( separated )
12532  (*result) = SCIP_SEPARATED;
12533  }
12534  else
12535  {
12536  SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12537  }
12538 
12539  return SCIP_OKAY;
12540 }
12541 
12542 /**@} */
12543 
12544 
12545 /**@name Callback methods of constraint handler
12546  *
12547  * @{
12548  */
12549 
12550 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12551 static
12552 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12553 { /*lint --e{715}*/
12554  assert(scip != NULL);
12555  assert(conshdlr != NULL);
12556  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12557 
12558  /* call inclusion method of constraint handler */
12560 
12562 
12563  *valid = TRUE;
12564 
12565  return SCIP_OKAY;
12566 }
12567 
12568 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12569 static
12570 SCIP_DECL_CONSFREE(consFreeCumulative)
12571 { /*lint --e{715}*/
12572  SCIP_CONSHDLRDATA* conshdlrdata;
12573 
12574  assert(conshdlr != NULL);
12575  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12576 
12577  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12578  assert(conshdlrdata != NULL);
12579 
12580 #ifdef SCIP_STATISTIC
12581  if( !conshdlrdata->iscopy )
12582  {
12583  /* statisitc output if SCIP_STATISTIC is defined */
12584  SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12585  conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12586  SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12587  conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12588  SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12589  conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12590  }
12591 #endif
12592 
12593  conshdlrdataFree(scip, &conshdlrdata);
12594 
12595  SCIPconshdlrSetData(conshdlr, NULL);
12596 
12597  return SCIP_OKAY;
12598 }
12599 
12600 
12601 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12602 static
12603 SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12604 { /*lint --e{715}*/
12605  SCIP_CONSHDLRDATA* conshdlrdata;
12606  int c;
12607 
12608  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12609  assert(conshdlrdata != NULL);
12610 
12611  conshdlrdata->detectedredundant = FALSE;
12612 
12613  for( c = 0; c < nconss; ++c )
12614  {
12615  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12616  * hmax)
12617  */
12618  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12619  }
12620 
12621  return SCIP_OKAY;
12622 }
12623 
12624 
12625 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12626 #ifdef SCIP_STATISTIC
12627 static
12628 SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12629 { /*lint --e{715}*/
12630  SCIP_CONSHDLRDATA* conshdlrdata;
12631  int c;
12632 
12633  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12634  assert(conshdlrdata != NULL);
12635 
12636  for( c = 0; c < nconss; ++c )
12637  {
12638  SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12639 
12640 #if 0
12641  SCIP_CALL( SCIPvisualizeConsCumulative(scip, conss[c]) );
12642 #endif
12643  }
12644 
12645  if( !conshdlrdata->iscopy )
12646  {
12647  SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12648  SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12649  SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12650  SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12651  SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12652  SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12653  SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12654  SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12655  SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12656  }
12657 
12658  return SCIP_OKAY;
12659 }
12660 #endif
12661 
12662 
12663 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12664 static
12665 SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12666 { /*lint --e{715}*/
12667  SCIP_CONSDATA* consdata;
12668  int c;
12669 
12670  assert(conshdlr != NULL);
12671  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12672 
12673  /* release the rows of all constraints */
12674  for( c = 0; c < nconss; ++c )
12675  {
12676  consdata = SCIPconsGetData(conss[c]);
12677  assert(consdata != NULL);
12678 
12679  /* free rows */
12680  SCIP_CALL( consdataFreeRows(scip, &consdata) );
12681  }
12682 
12683  return SCIP_OKAY;
12684 }
12685 
12686 /** frees specific constraint data */
12687 static
12688 SCIP_DECL_CONSDELETE(consDeleteCumulative)
12689 { /*lint --e{715}*/
12690  assert(conshdlr != NULL);
12691  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12692  assert(consdata != NULL );
12693  assert(*consdata != NULL );
12694 
12695  /* if constraint belongs to transformed problem space, drop bound change events on variables */
12696  if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12697  {
12698  SCIP_CONSHDLRDATA* conshdlrdata;
12699 
12700  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12701  assert(conshdlrdata != NULL);
12702 
12703  SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12704  }
12705 
12706  /* free cumulative constraint data */
12707  SCIP_CALL( consdataFree(scip, consdata) );
12708 
12709  return SCIP_OKAY;
12710 }
12711 
12712 /** transforms constraint data into data belonging to the transformed problem */
12713 static
12714 SCIP_DECL_CONSTRANS(consTransCumulative)
12715 { /*lint --e{715}*/
12716  SCIP_CONSHDLRDATA* conshdlrdata;
12717  SCIP_CONSDATA* sourcedata;
12718  SCIP_CONSDATA* targetdata;
12719 
12720  assert(conshdlr != NULL);
12721  assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
12722  assert(sourcecons != NULL);
12723  assert(targetcons != NULL);
12724 
12725  sourcedata = SCIPconsGetData(sourcecons);
12726  assert(sourcedata != NULL);
12727  assert(sourcedata->demandrows == NULL);
12728 
12729  SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12730 
12731  /* get event handler */
12732  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12733  assert(conshdlrdata != NULL);
12734  assert(conshdlrdata->eventhdlr != NULL);
12735 
12736  /* create constraint data for target constraint */
12737  SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12738  sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12739  sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12740 
12741  /* create target constraint */
12742  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12743  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12744  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12745  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12746  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12747 
12748  /* catch bound change events of variables */
12749  SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12750 
12751  return SCIP_OKAY;
12752 }
12753 
12754 /** LP initialization method of constraint handler */
12755 static
12756 SCIP_DECL_CONSINITLP(consInitlpCumulative)
12758  SCIP_CONSHDLRDATA* conshdlrdata;
12759  int c;
12760 
12761  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12762  assert(conshdlr != NULL);
12763  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12764  assert(conshdlrdata != NULL);
12765 
12766  *infeasible = FALSE;
12767 
12768  SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12769 
12770  if( conshdlrdata->usebinvars )
12771  {
12772  /* add rows to LP */
12773  for( c = 0; c < nconss && !(*infeasible); ++c )
12774  {
12775  assert(SCIPconsIsInitial(conss[c]));
12776  SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12777 
12778  if( conshdlrdata->cutsasconss )
12779  {
12780  SCIP_CALL( SCIPrestartSolve(scip) );
12781  }
12782  }
12783  }
12784 
12785  /**@todo if we want to use only the integer variables; only these will be in cuts
12786  * create some initial cuts, currently these are only separated */
12787 
12788  return SCIP_OKAY;
12789 }
12790 
12791 /** separation method of constraint handler for LP solutions */
12792 static
12793 SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12795  SCIP_CONSHDLRDATA* conshdlrdata;
12796  SCIP_Bool cutoff;
12797  SCIP_Bool separated;
12798  int c;
12799 
12800  SCIPdebugMsg(scip, "consSepalpCumulative\n");
12801 
12802  assert(conshdlr != NULL);
12803  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12804  assert(nconss == 0 || conss != NULL);
12805  assert(result != NULL);
12806  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12807  assert(conshdlrdata != NULL);
12808 
12809  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12810 
12811  cutoff = FALSE;
12812  separated = FALSE;
12813  (*result) = SCIP_DIDNOTRUN;
12814 
12815  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12816  return SCIP_OKAY;
12817 
12818  (*result) = SCIP_DIDNOTFIND;
12819 
12820  if( conshdlrdata->usebinvars )
12821  {
12822  /* check all useful cumulative constraints for feasibility */
12823  for( c = 0; c < nusefulconss && !cutoff; ++c )
12824  {
12825  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12826  }
12827 
12828  if( !cutoff && conshdlrdata->usecovercuts )
12829  {
12830  for( c = 0; c < nusefulconss; ++c )
12831  {
12832  SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12833  }
12834  }
12835  }
12836 
12837  if( conshdlrdata->sepaold )
12838  {
12839  /* separate cuts containing only integer variables */
12840  for( c = 0; c < nusefulconss; ++c )
12841  {
12842  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated) );
12843  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated) );
12844  }
12845  }
12846 
12847  if( cutoff )
12848  *result = SCIP_CUTOFF;
12849  else if( separated )
12850  *result = SCIP_SEPARATED;
12851 
12852  return SCIP_OKAY;
12853 }
12854 
12855 /** separation method of constraint handler for arbitrary primal solutions */
12856 static
12857 SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12858 { /*lint --e{715}*/
12859  SCIP_CONSHDLRDATA* conshdlrdata;
12860  SCIP_Bool cutoff;
12861  SCIP_Bool separated;
12862  int c;
12863 
12864  assert(conshdlr != NULL);
12865  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12866  assert(nconss == 0 || conss != NULL);
12867  assert(result != NULL);
12868 
12869  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12870  assert(conshdlrdata != NULL);
12871 
12872  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12873  return SCIP_OKAY;
12874 
12875  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12876 
12877  cutoff = FALSE;
12878  separated = FALSE;
12879  (*result) = SCIP_DIDNOTFIND;
12880 
12881  if( conshdlrdata->usebinvars )
12882  {
12883  /* check all useful cumulative constraints for feasibility */
12884  for( c = 0; c < nusefulconss && !cutoff; ++c )
12885  {
12886  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12887  }
12888 
12889  if( !cutoff && conshdlrdata->usecovercuts )
12890  {
12891  for( c = 0; c < nusefulconss; ++c )
12892  {
12893  SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12894  }
12895  }
12896  }
12897  if( conshdlrdata->sepaold )
12898  {
12899  /* separate cuts containing only integer variables */
12900  for( c = 0; c < nusefulconss; ++c )
12901  {
12902  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated) );
12903  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated) );
12904  }
12905  }
12906 
12907  if( cutoff )
12908  *result = SCIP_CUTOFF;
12909  else if( separated )
12910  *result = SCIP_SEPARATED;
12911 
12912  return SCIP_OKAY;
12913 }
12914 
12915 /** constraint enforcing method of constraint handler for LP solutions */
12916 static
12917 SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
12918 { /*lint --e{715}*/
12919  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
12920 
12921  return SCIP_OKAY;
12922 }
12923 
12924 /** constraint enforcing method of constraint handler for relaxation solutions */
12925 static
12926 SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
12927 { /*lint --e{715}*/
12928  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
12929 
12930  return SCIP_OKAY;
12931 }
12932 
12933 /** constraint enforcing method of constraint handler for pseudo solutions */
12934 static
12935 SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
12936 { /*lint --e{715}*/
12937  SCIP_CONSHDLRDATA* conshdlrdata;
12938 
12939  SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
12940 
12941  assert(conshdlr != NULL);
12942  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12943  assert(nconss == 0 || conss != NULL);
12944  assert(result != NULL);
12945 
12946  if( objinfeasible )
12947  {
12948  *result = SCIP_DIDNOTRUN;
12949  return SCIP_OKAY;
12950  }
12951 
12952  (*result) = SCIP_FEASIBLE;
12953 
12954  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12955  assert(conshdlrdata != NULL);
12956 
12957  SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
12958 
12959  return SCIP_OKAY;
12960 }
12961 
12962 /** feasibility check method of constraint handler for integral solutions */
12963 static
12964 SCIP_DECL_CONSCHECK(consCheckCumulative)
12965 { /*lint --e{715}*/
12966  int c;
12967 
12968  assert(conshdlr != NULL);
12969  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12970  assert(nconss == 0 || conss != NULL);
12971  assert(result != NULL);
12972 
12973  *result = SCIP_FEASIBLE;
12974 
12975  SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
12976 
12977  for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
12978  {
12979  SCIP_Bool violated = FALSE;
12980 
12981  SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
12982 
12983  if( violated )
12984  *result = SCIP_INFEASIBLE;
12985  }
12986 
12987  return SCIP_OKAY;
12988 }
12989 
12990 /** domain propagation method of constraint handler */
12991 static
12992 SCIP_DECL_CONSPROP(consPropCumulative)
12993 { /*lint --e{715}*/
12994  SCIP_CONSHDLRDATA* conshdlrdata;
12995  SCIP_Bool cutoff;
12996  int nchgbds;
12997  int ndelconss;
12998  int c;
12999 #if 0
13000  int naggrvars = 0;
13001 #endif
13002 
13003  SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
13004 
13005  assert(conshdlr != NULL);
13006  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13007  assert(nconss == 0 || conss != NULL);
13008  assert(result != NULL);
13009 
13010  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13011  assert(conshdlrdata != NULL);
13012 
13013  nchgbds = 0;
13014  ndelconss = 0;
13015  cutoff = FALSE;
13016  (*result) = SCIP_DIDNOTRUN;
13017 
13018  /* propgate all useful constraints */
13019  for( c = 0; c < nusefulconss && !cutoff; ++c )
13020  {
13021  SCIP_CONS* cons;
13022 
13023  cons = conss[c];
13024  assert(cons != NULL);
13025 
13026  if( SCIPgetDepth(scip) == 0 )
13027  {
13028 #if 0
13029  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13030  &nchgbds, &naggrvars, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13031 #else
13032  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13033  &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13034 #endif
13035  if( cutoff )
13036  break;
13037 
13038  if( SCIPconsIsDeleted(cons) )
13039  continue;
13040  }
13041 
13042  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13043  }
13044 
13045  if( !cutoff && nchgbds == 0 )
13046  {
13047  /* propgate all other constraints */
13048  for( c = nusefulconss; c < nconss && !cutoff; ++c )
13049  {
13050  SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13051  }
13052  }
13053 
13054 #if 0
13055  if( !cutoff && conshdlrdata->dualpresolve && SCIPallowDualReds(scip) && nconss > 1 )
13056  {
13057  SCIP_CALL( propagateAllConss(scip, conshdlrdata, conss, nconss, TRUE, &nchgbds, &cutoff, NULL) );
13058  }
13059 #endif
13060 
13061  if( cutoff )
13062  {
13063  SCIPdebugMsg(scip, "detected infeasible\n");
13064  *result = SCIP_CUTOFF;
13065  }
13066  else if( nchgbds > 0 )
13067  {
13068  SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13069  *result = SCIP_REDUCEDDOM;
13070  }
13071  else
13072  *result = SCIP_DIDNOTFIND;
13073 
13074  return SCIP_OKAY;
13075 }
13076 
13077 /** presolving method of constraint handler */
13078 static
13079 SCIP_DECL_CONSPRESOL(consPresolCumulative)
13080 { /*lint --e{715}*/
13081  SCIP_CONSHDLRDATA* conshdlrdata;
13082  SCIP_CONS* cons;
13083  SCIP_Bool cutoff;
13084  SCIP_Bool unbounded;
13085  int oldnfixedvars;
13086  int oldnchgbds;
13087  int oldndelconss;
13088  int oldnaddconss;
13089  int oldnupgdconss;
13090  int oldnchgsides;
13091  int oldnchgcoefs;
13092  int c;
13093 
13094  assert(conshdlr != NULL);
13095  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13096  assert(scip != NULL);
13097  assert(result != NULL);
13098 
13099  SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13100 
13101  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13102  assert(conshdlrdata != NULL);
13103 
13104  *result = SCIP_DIDNOTRUN;
13105 
13106  oldnfixedvars = *nfixedvars;
13107  oldnchgbds = *nchgbds;
13108  oldnchgsides = *nchgsides;
13109  oldnchgcoefs = *nchgcoefs;
13110  oldnupgdconss = *nupgdconss;
13111  oldndelconss = *ndelconss;
13112  oldnaddconss = *naddconss;
13113  cutoff = FALSE;
13114  unbounded = FALSE;
13115 
13116  /* process constraints */
13117  for( c = 0; c < nconss && !cutoff; ++c )
13118  {
13119  cons = conss[c];
13120 
13121  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13122  * hmax)
13123  */
13124  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13125 
13126  if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13127  {
13128 #if 0
13129  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13130  nfixedvars, naggrvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13131 #else
13132  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13133  nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13134 #endif
13135 
13136  if( cutoff || unbounded )
13137  break;
13138 
13139  if( SCIPconsIsDeleted(cons) )
13140  continue;
13141  }
13142 
13143  /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13144  if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13145  {
13146  SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13147  }
13148 
13149  /* strengthen existing variable bounds using the cumulative condition */
13150  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13151  {
13152  SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13153  }
13154 
13155  /* propagate cumulative constraint */
13156  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13157  assert(checkDemands(scip, cons) || cutoff);
13158  }
13159 
13160  if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13161  {
13162  SCIP_CALL( propagateAllConss(scip, conshdlrdata, conss, nconss, FALSE,
13163  nfixedvars, &cutoff, NULL) );
13164  }
13165 
13166  /* only perform the detection of variable bounds and disjunctive constraint once */
13167  if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13168  && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13169  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13170  {
13171  /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13172  * propagation
13173  */
13174  SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13175  conshdlrdata->detectedredundant = TRUE;
13176  }
13177 
13178  if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13179  {
13180  SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13181  }
13182 
13183  SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13184  *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13185 
13186  if( cutoff )
13187  *result = SCIP_CUTOFF;
13188  else if( unbounded )
13189  *result = SCIP_UNBOUNDED;
13190  else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13191  || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13192  *result = SCIP_SUCCESS;
13193  else
13194  *result = SCIP_DIDNOTFIND;
13195 
13196  return SCIP_OKAY;
13197 }
13198 
13199 /** propagation conflict resolving method of constraint handler */
13200 static
13201 SCIP_DECL_CONSRESPROP(consRespropCumulative)
13202 { /*lint --e{715}*/
13203  SCIP_CONSHDLRDATA* conshdlrdata;
13204  SCIP_CONSDATA* consdata;
13205 
13206  assert(conshdlr != NULL);
13207  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13208  assert(scip != NULL);
13209  assert(result != NULL);
13210  assert(infervar != NULL);
13211  assert(bdchgidx != NULL);
13212 
13213  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13214  assert(conshdlrdata != NULL);
13215 
13216  /* process constraint */
13217  assert(cons != NULL);
13218 
13219  consdata = SCIPconsGetData(cons);
13220  assert(consdata != NULL);
13221 
13222  SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13223  SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13224  SCIPgetHminCumulative(scip, cons), SCIPgetHmaxCumulative(scip, cons));
13225 
13226  SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13227  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13228  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13229 
13230  return SCIP_OKAY;
13231 }
13232 
13233 /** variable rounding lock method of constraint handler */
13234 static
13235 SCIP_DECL_CONSLOCK(consLockCumulative)
13236 { /*lint --e{715}*/
13237  SCIP_CONSDATA* consdata;
13238  SCIP_VAR** vars;
13239  int v;
13240 
13241  SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13242 
13243  assert(scip != NULL);
13244  assert(cons != NULL);
13245 
13246  consdata = SCIPconsGetData(cons);
13247  assert(consdata != NULL);
13248 
13249  vars = consdata->vars;
13250  assert(vars != NULL);
13251 
13252  for( v = 0; v < consdata->nvars; ++v )
13253  {
13254  if( consdata->downlocks[v] && consdata->uplocks[v] )
13255  {
13256  /* the integer start variable should not get rounded in both direction */
13257  SCIP_CALL( SCIPaddVarLocks(scip, vars[v], nlockspos + nlocksneg, nlockspos + nlocksneg) );
13258  }
13259  else if( consdata->downlocks[v] )
13260  {
13261  SCIP_CALL( SCIPaddVarLocks(scip, vars[v], nlockspos, nlocksneg) );
13262  }
13263  else if( consdata->uplocks[v] )
13264  {
13265  SCIP_CALL( SCIPaddVarLocks(scip, vars[v], nlocksneg, nlockspos) );
13266  }
13267  }
13268 
13269  return SCIP_OKAY;
13270 }
13271 
13272 
13273 /** constraint display method of constraint handler */
13274 static
13275 SCIP_DECL_CONSPRINT(consPrintCumulative)
13276 { /*lint --e{715}*/
13277  assert(scip != NULL);
13278  assert(conshdlr != NULL);
13279  assert(cons != NULL);
13280 
13281  consdataPrint(scip, SCIPconsGetData(cons), file);
13282 
13283  return SCIP_OKAY;
13284 }
13285 
13286 /** constraint copying method of constraint handler */
13287 static
13288 SCIP_DECL_CONSCOPY(consCopyCumulative)
13289 { /*lint --e{715}*/
13290  SCIP_CONSDATA* sourceconsdata;
13291  SCIP_VAR** sourcevars;
13292  SCIP_VAR** vars;
13293  const char* consname;
13294 
13295  int nvars;
13296  int v;
13297 
13298  sourceconsdata = SCIPconsGetData(sourcecons);
13299  assert(sourceconsdata != NULL);
13300 
13301  /* get variables of the source constraint */
13302  nvars = sourceconsdata->nvars;
13303  sourcevars = sourceconsdata->vars;
13304 
13305  (*valid) = TRUE;
13306 
13307  if( nvars == 0 )
13308  return SCIP_OKAY;
13309 
13310  /* allocate buffer array */
13311  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13312 
13313  for( v = 0; v < nvars && *valid; ++v )
13314  {
13315  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13316  assert(!(*valid) || vars[v] != NULL);
13317  }
13318 
13319  /* only create the target constraint, if all variables could be copied */
13320  if( *valid )
13321  {
13322  if( name != NULL )
13323  consname = name;
13324  else
13325  consname = SCIPconsGetName(sourcecons);
13326 
13327  /* create a copy of the cumulative constraint */
13328  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13329  sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13330  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13331 
13332  /* adjust left side if the time axis if needed */
13333  if( sourceconsdata->hmin > 0 )
13334  {
13335  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13336  }
13337 
13338  /* adjust right side if the time axis if needed */
13339  if( sourceconsdata->hmax < INT_MAX )
13340  {
13341  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13342  }
13343  }
13344 
13345  /* free buffer array */
13346  SCIPfreeBufferArray(scip, &vars);
13347 
13348  return SCIP_OKAY;
13349 }
13350 
13351 
13352 /** constraint parsing method of constraint handler */
13353 static
13354 SCIP_DECL_CONSPARSE(consParseCumulative)
13355 { /*lint --e{715}*/
13356  SCIP_VAR** vars;
13357  SCIP_VAR* var;
13358  SCIP_Real value;
13359  char strvalue[SCIP_MAXSTRLEN];
13360  char* endptr;
13361  int* demands;
13362  int* durations;
13363  int capacity;
13364  int duration;
13365  int demand;
13366  int hmin;
13367  int hmax;
13368  int varssize;
13369  int nvars;
13370 
13371  SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13372 
13373  /* cutoff "cumulative" form the constraint string */
13374  SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13375  str = endptr;
13376 
13377  varssize = 100;
13378  nvars = 0;
13379 
13380  /* allocate buffer array for variables */
13381  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13382  SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13383  SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13384 
13385  do
13386  {
13387  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13388 
13389  if( var != NULL )
13390  {
13391  str = endptr;
13392 
13393  SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13394  duration = atoi(strvalue);
13395  str = endptr;
13396 
13397  SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13398  demand = atoi(strvalue);
13399  str = endptr;
13400 
13401  SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13402 
13403  vars[nvars] = var;
13404  demands[nvars] = demand;
13405  durations[nvars] = duration;
13406  nvars++;
13407  }
13408  }
13409  while( var != NULL );
13410 
13411  /* parse effective time window */
13412  SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13413  hmin = atoi(strvalue);
13414  str = endptr;
13415 
13416  if( SCIPstrToRealValue(str, &value, &endptr) )
13417  {
13418  hmax = (int)(value);
13419  str = endptr;
13420 
13421  /* parse capacity */
13422  SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13423  str = endptr;
13424  if( SCIPstrToRealValue(str, &value, &endptr) )
13425  {
13426  capacity = (int)value;
13427 
13428  /* create cumulative constraint */
13429  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13430  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13431 
13432  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13433  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13434 
13435  (*success) = TRUE;
13436  }
13437  }
13438 
13439  /* free buffer arrays */
13440  SCIPfreeBufferArray(scip, &durations);
13441  SCIPfreeBufferArray(scip, &demands);
13442  SCIPfreeBufferArray(scip, &vars);
13443 
13444  return SCIP_OKAY;
13445 }
13446 
13447 /** constraint method of constraint handler which returns the variables (if possible) */
13448 static
13449 SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13450 { /*lint --e{715}*/
13451  SCIP_CONSDATA* consdata;
13452 
13453  consdata = SCIPconsGetData(cons);
13454  assert(consdata != NULL);
13455 
13456  if( varssize < consdata->nvars )
13457  (*success) = FALSE;
13458  else
13459  {
13460  assert(vars != NULL);
13461 
13462  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13463  (*success) = TRUE;
13464  }
13465 
13466  return SCIP_OKAY;
13467 }
13468 
13469 /** constraint method of constraint handler which returns the number of variables (if possible) */
13470 static
13471 SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13472 { /*lint --e{715}*/
13473  SCIP_CONSDATA* consdata;
13474 
13475  consdata = SCIPconsGetData(cons);
13476  assert(consdata != NULL);
13477 
13478  (*nvars) = consdata->nvars;
13479  (*success) = TRUE;
13480 
13481  return SCIP_OKAY;
13482 }
13483 
13484 /**@} */
13485 
13486 /**@name Callback methods of event handler
13487  *
13488  * @{
13489  */
13490 
13491 
13492 /** execution method of event handler */
13493 static
13494 SCIP_DECL_EVENTEXEC(eventExecCumulative)
13495 { /*lint --e{715}*/
13496  SCIP_CONSDATA* consdata;
13497 
13498  assert(scip != NULL);
13499  assert(eventhdlr != NULL);
13500  assert(eventdata != NULL);
13501  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13502  assert(event != NULL);
13503 
13504  consdata = (SCIP_CONSDATA*)eventdata;
13505  assert(consdata != NULL);
13506 
13507  /* mark the constraint to be not propagated */
13508  consdata->propagated = FALSE;
13509 
13510  return SCIP_OKAY;
13511 }
13512 
13513 /**@} */
13514 
13515 /**@name Interface methods
13516  *
13517  * @{
13518  */
13519 
13520 /*
13521  * constraint specific interface methods
13522  */
13523 
13524 /** creates the handler for cumulative constraints and includes it in SCIP */
13526  SCIP* scip /**< SCIP data structure */
13527  )
13528 {
13529  SCIP_CONSHDLRDATA* conshdlrdata;
13530  SCIP_CONSHDLR* conshdlr;
13531  SCIP_EVENTHDLR* eventhdlr;
13532 
13533  /* create event handler for bound change events */
13534  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13535 
13536  /* create cumulative constraint handler data */
13537  SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13538 
13539  /* include constraint handler */
13542  consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13543  conshdlrdata) );
13544 
13545  assert(conshdlr != NULL);
13546 
13547  /* set non-fundamental callbacks via specific setter functions */
13548  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13549  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13550 #ifdef SCIP_STATISTIC
13551  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13552 #endif
13553  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13554  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13555  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13556  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13557  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13558  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13559  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13560  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13562  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13563  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropCumulative, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13565  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13566  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13568  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13569  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
13570 
13571  /* add cumulative constraint handler parameters */
13573  "constraints/" CONSHDLR_NAME "/ttinfer",
13574  "should time-table (core-times) propagator be used to infer bounds?",
13575  &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13577  "constraints/" CONSHDLR_NAME "/efcheck",
13578  "should edge-finding be used to detect an overload?",
13579  &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13581  "constraints/" CONSHDLR_NAME "/efinfer",
13582  "should edge-finding be used to infer bounds?",
13583  &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13585  "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13586  &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13588  "constraints/" CONSHDLR_NAME "/ttefcheck",
13589  "should time-table edge-finding be used to detect an overload?",
13590  &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13592  "constraints/" CONSHDLR_NAME "/ttefinfer",
13593  "should time-table edge-finding be used to infer bounds?",
13594  &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13595 
13597  "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13598  &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13600  "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13601  &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13603  "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13604  &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13606  "constraints/" CONSHDLR_NAME "/cutsasconss",
13607  "should the cumulative constraint create cuts as knapsack constraints?",
13608  &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13610  "constraints/" CONSHDLR_NAME "/sepaold",
13611  "shall old sepa algo be applied?",
13612  &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13613 
13615  "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13616  &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13617 
13618  /* presolving parameters */
13620  "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13621  &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13623  "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13624  &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13626  "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13627  &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13629  "constraints/" CONSHDLR_NAME "/presolpairwise",
13630  "should pairwise constraint comparison be performed in presolving?",
13631  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13633  "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13634  &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13635 
13637  "constraints/" CONSHDLR_NAME "/maxnodes",
13638  "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13639  &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13641  "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13642  &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13644  "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13645  &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13646 
13647  /* conflict analysis parameters */
13649  "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13650  &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13651 
13652  return SCIP_OKAY;
13653 }
13654 
13655 /** creates and captures a cumulative constraint */
13657  SCIP* scip, /**< SCIP data structure */
13658  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13659  const char* name, /**< name of constraint */
13660  int nvars, /**< number of variables (jobs) */
13661  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13662  int* durations, /**< array containing corresponding durations */
13663  int* demands, /**< array containing corresponding demands */
13664  int capacity, /**< available cumulative capacity */
13665  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13666  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13667  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13668  * Usually set to TRUE. */
13669  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13670  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13671  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13672  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13673  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13674  * Usually set to TRUE. */
13675  SCIP_Bool local, /**< is constraint only valid locally?
13676  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13677  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13678  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13679  * adds coefficients to this constraint. */
13680  SCIP_Bool dynamic, /**< is constraint subject to aging?
13681  * Usually set to FALSE. Set to TRUE for own cuts which
13682  * are seperated as constraints. */
13683  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13684  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13685  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13686  * if it may be moved to a more global node?
13687  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13688  )
13689 {
13690  SCIP_CONSHDLR* conshdlr;
13691  SCIP_CONSDATA* consdata;
13692 
13693  assert(scip != NULL);
13694 
13695  /* find the cumulative constraint handler */
13696  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13697  if( conshdlr == NULL )
13698  {
13699  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13700  return SCIP_PLUGINNOTFOUND;
13701  }
13702 
13703  SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13704 
13705  /* create constraint data */
13706  SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13707 
13708  /* create constraint */
13709  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13710  initial, separate, enforce, check, propagate,
13711  local, modifiable, dynamic, removable, stickingatnode) );
13712 
13713 
13714  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13715  {
13716  SCIP_CONSHDLRDATA* conshdlrdata;
13717 
13718  /* get event handler */
13719  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13720  assert(conshdlrdata != NULL);
13721  assert(conshdlrdata->eventhdlr != NULL);
13722 
13723  /* catch bound change events of variables */
13724  SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13725  }
13726 
13727  return SCIP_OKAY;
13728 }
13729 
13730 /** creates and captures a cumulative constraint
13731  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13732  * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13733  *
13734  * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13735  *
13736  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13737  */
13739  SCIP* scip, /**< SCIP data structure */
13740  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13741  const char* name, /**< name of constraint */
13742  int nvars, /**< number of variables (jobs) */
13743  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13744  int* durations, /**< array containing corresponding durations */
13745  int* demands, /**< array containing corresponding demands */
13746  int capacity /**< available cumulative capacity */
13747  )
13748 {
13749  assert(scip != NULL);
13750 
13751  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13752  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13753 
13754  return SCIP_OKAY;
13755 }
13756 
13757 /** set the left bound of the time axis to be considered (including hmin) */
13759  SCIP* scip, /**< SCIP data structure */
13760  SCIP_CONS* cons, /**< constraint data */
13761  int hmin /**< left bound of time axis to be considered */
13762  )
13763 {
13764  SCIP_CONSDATA* consdata;
13765  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13766  {
13767  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13768  return SCIP_INVALIDCALL;
13769  }
13770 
13771  consdata = SCIPconsGetData(cons);
13772  assert(consdata != NULL);
13773  assert(hmin >= 0);
13774  assert(hmin <= consdata->hmax);
13775 
13776  consdata->hmin = hmin;
13777 
13778  return SCIP_OKAY;
13779 }
13780 
13781 /** returns the left bound of the time axis to be considered */
13783  SCIP* scip, /**< SCIP data structure */
13784  SCIP_CONS* cons /**< constraint */
13785  )
13786 {
13787  SCIP_CONSDATA* consdata;
13788  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13789  {
13790  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13791  SCIPABORT();
13792  return 0; /*lint !e527*/
13793  }
13794 
13795  consdata = SCIPconsGetData(cons);
13796  assert(consdata != NULL);
13797 
13798  return consdata->hmin;
13799 }
13800 
13801 /** set the right bound of the time axis to be considered (not including hmax) */
13803  SCIP* scip, /**< SCIP data structure */
13804  SCIP_CONS* cons, /**< constraint data */
13805  int hmax /**< right bound of time axis to be considered */
13806  )
13807 {
13808  SCIP_CONSDATA* consdata;
13809  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13810  {
13811  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13812  SCIPABORT();
13813  return SCIP_INVALIDCALL; /*lint !e527*/
13814  }
13815 
13816  consdata = SCIPconsGetData(cons);
13817  assert(consdata != NULL);
13818  assert(hmax >= consdata->hmin);
13819 
13820  consdata->hmax = hmax;
13821 
13822  return SCIP_OKAY;
13823 }
13824 
13825 /** returns the right bound of the time axis to be considered */
13827  SCIP* scip, /**< SCIP data structure */
13828  SCIP_CONS* cons /**< constraint */
13829  )
13830 {
13831  SCIP_CONSDATA* consdata;
13832  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13833  {
13834  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13835  SCIPABORT();
13836  return 0; /*lint !e527*/
13837  }
13838 
13839  consdata = SCIPconsGetData(cons);
13840  assert(consdata != NULL);
13841 
13842  return consdata->hmax;
13843 }
13844 
13845 /** returns the activities of the cumulative constraint */
13847  SCIP* scip, /**< SCIP data structure */
13848  SCIP_CONS* cons /**< constraint data */
13849  )
13850 {
13851  SCIP_CONSDATA* consdata;
13852 
13853  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13854  {
13855  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13856  SCIPABORT();
13857  return NULL; /*lint !e527*/
13858  }
13859 
13860  consdata = SCIPconsGetData(cons);
13861  assert(consdata != NULL);
13862 
13863  return consdata->vars;
13864 }
13865 
13866 /** returns the activities of the cumulative constraint */
13868  SCIP* scip, /**< SCIP data structure */
13869  SCIP_CONS* cons /**< constraint data */
13870  )
13871 {
13872  SCIP_CONSDATA* consdata;
13873 
13874  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13875  {
13876  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13877  SCIPABORT();
13878  return -1; /*lint !e527*/
13879  }
13880 
13881  consdata = SCIPconsGetData(cons);
13882  assert(consdata != NULL);
13883 
13884  return consdata->nvars;
13885 }
13886 
13887 /** returns the capacity of the cumulative constraint */
13889  SCIP* scip, /**< SCIP data structure */
13890  SCIP_CONS* cons /**< constraint data */
13891  )
13892 {
13893  SCIP_CONSDATA* consdata;
13894 
13895  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13896  {
13897  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13898  SCIPABORT();
13899  return -1; /*lint !e527*/
13900  }
13901 
13902  consdata = SCIPconsGetData(cons);
13903  assert(consdata != NULL);
13904 
13905  return consdata->capacity;
13906 }
13907 
13908 /** returns the durations of the cumulative constraint */
13910  SCIP* scip, /**< SCIP data structure */
13911  SCIP_CONS* cons /**< constraint data */
13912  )
13913 {
13914  SCIP_CONSDATA* consdata;
13915 
13916  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13917  {
13918  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13919  SCIPABORT();
13920  return NULL; /*lint !e527*/
13921  }
13922 
13923  consdata = SCIPconsGetData(cons);
13924  assert(consdata != NULL);
13925 
13926  return consdata->durations;
13927 }
13928 
13929 /** returns the demands of the cumulative constraint */
13931  SCIP* scip, /**< SCIP data structure */
13932  SCIP_CONS* cons /**< constraint data */
13933  )
13934 {
13935  SCIP_CONSDATA* consdata;
13936 
13937  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13938  {
13939  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13940  SCIPABORT();
13941  return NULL; /*lint !e527*/
13942  }
13943 
13944  consdata = SCIPconsGetData(cons);
13945  assert(consdata != NULL);
13946 
13947  return consdata->demands;
13948 }
13949 
13950 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
13951  * given solution is satisfied
13952  */
13954  SCIP* scip, /**< SCIP data structure */
13955  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
13956  int nvars, /**< number of variables (jobs) */
13957  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13958  int* durations, /**< array containing corresponding durations */
13959  int* demands, /**< array containing corresponding demands */
13960  int capacity, /**< available cumulative capacity */
13961  int hmin, /**< left bound of time axis to be considered (including hmin) */
13962  int hmax, /**< right bound of time axis to be considered (not including hmax) */
13963  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
13964  SCIP_CONS* cons, /**< constraint which is checked */
13965  SCIP_Bool printreason /**< should the reason for the violation be printed? */
13966  )
13967 {
13968  assert(scip != NULL);
13969  assert(violated != NULL);
13970 
13971  SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
13972  violated, cons, printreason) );
13973 
13974  return SCIP_OKAY;
13975 }
13976 
13977 /** normalize cumulative condition */
13979  SCIP* scip, /**< SCIP data structure */
13980  int nvars, /**< number of start time variables (activities) */
13981  SCIP_VAR** vars, /**< array of start time variables */
13982  int* durations, /**< array of durations */
13983  int* demands, /**< array of demands */
13984  int* capacity, /**< pointer to store the changed cumulative capacity */
13985  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
13986  int* nchgsides /**< pointer to count number of side changes */
13987  )
13988 {
13989  SCIP_CALL( normalizeCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
13990  nchgcoefs, nchgsides) );
13991 
13992  return SCIP_OKAY;
13993 }
13994 
13995 /** searches for a time point within the cumulative condition were the cumulative condition can be split */
13997  SCIP* scip, /**< SCIP data structure */
13998  int nvars, /**< number of variables (jobs) */
13999  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14000  int* durations, /**< array containing corresponding durations */
14001  int* demands, /**< array containing corresponding demands */
14002  int capacity, /**< available cumulative capacity */
14003  int* hmin, /**< pointer to store the left bound of the effective horizon */
14004  int* hmax, /**< pointer to store the right bound of the effective horizon */
14005  int* split /**< point were the cumulative condition can be split */
14006  )
14007 {
14008  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14009  hmin, hmax, split) );
14010 
14011  return SCIP_OKAY;
14012 }
14013 
14014 /** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
14016  SCIP* scip, /**< SCIP data structure */
14017  int nvars, /**< number of start time variables (activities) */
14018  SCIP_VAR** vars, /**< array of start time variables */
14019  int* durations, /**< array of durations */
14020  int hmin, /**< left bound of time axis to be considered */
14021  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14022  SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
14023  SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
14024  SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
14025  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
14026  int* nfixedvars, /**< pointer to store the number of fixed variables */
14027  int* nchgsides, /**< pointer to store the number of changed sides */
14028  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
14029  )
14030 {
14031  if( nvars <= 1 )
14032  return SCIP_OKAY;
14033 
14034  /* presolve constraint form the earlier start time point of view */
14035  SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14036  irrelevants, nfixedvars, nchgsides, cutoff) );
14037 
14038  /* presolve constraint form the latest completion time point of view */
14039  SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14040  irrelevants, nfixedvars, nchgsides, cutoff) );
14041 
14042  return SCIP_OKAY;
14043 }
14044 
14045 /** propagate the given cumulative condition */
14047  SCIP* scip, /**< SCIP data structure */
14048  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
14049  int nvars, /**< number of variables (jobs) */
14050  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14051  int* durations, /**< array containing corresponding durations */
14052  int* demands, /**< array containing corresponding demands */
14053  int capacity, /**< available cumulative capacity */
14054  int hmin, /**< left bound of time axis to be considered (including hmin) */
14055  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14056  SCIP_CONS* cons, /**< constraint which gets propagated */
14057  int* nchgbds, /**< pointer to store the number of variable bound changes */
14058  SCIP_Bool* initialized, /**< was conflict analysis initialized */
14059  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14060  SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14061  )
14062 {
14063  SCIP_CONSHDLR* conshdlr;
14064  SCIP_CONSHDLRDATA* conshdlrdata;
14065  SCIP_Bool redundant;
14066 
14067  assert(scip != NULL);
14068  assert(cons != NULL);
14069  assert(initialized != NULL);
14070  assert(*initialized == FALSE);
14071  assert(cutoff != NULL);
14072  assert(*cutoff == FALSE);
14073 
14074  /* find the cumulative constraint handler */
14075  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14076  if( conshdlr == NULL )
14077  {
14078  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14079  return SCIP_PLUGINNOTFOUND;
14080  }
14081 
14082  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14083  assert(conshdlrdata != NULL);
14084 
14085  redundant = FALSE;
14086 
14087  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14088  nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14089  nchgbds, &redundant, initialized, explanation, cutoff) );
14090 
14091  return SCIP_OKAY;
14092 }
14093 
14094 /** resolve propagation w.r.t. the cumulative condition */
14096  SCIP* scip, /**< SCIP data structure */
14097  int nvars, /**< number of start time variables (activities) */
14098  SCIP_VAR** vars, /**< array of start time variables */
14099  int* durations, /**< array of durations */
14100  int* demands, /**< array of demands */
14101  int capacity, /**< cumulative capacity */
14102  int hmin, /**< left bound of time axis to be considered (including hmin) */
14103  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14104  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14105  int inferinfo, /**< the user information */
14106  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14107  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14108  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14109  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14110  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14111  )
14112 {
14113  SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14114  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14115 
14116  return SCIP_OKAY;
14117 }
14118 
14119 /** this method visualizes the cumulative structure in GML format */
14121  SCIP* scip, /**< SCIP data structure */
14122  SCIP_CONS* cons /**< cumulative constraint */
14123  )
14124 {
14125  SCIP_CONSDATA* consdata;
14126  SCIP_HASHTABLE* vars;
14127  FILE* file;
14128  SCIP_VAR* var;
14129  char filename[SCIP_MAXSTRLEN];
14130  int nvars;
14131  int v;
14132 
14133  SCIP_RETCODE retcode = SCIP_OKAY;
14134 
14135  /* open file */
14136  (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14137  file = fopen(filename, "w");
14138 
14139  /* check if the file was open */
14140  if( file == NULL )
14141  {
14142  SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14143  SCIPprintSysError(filename);
14144  return SCIP_FILECREATEERROR;
14145  }
14146 
14147  consdata = SCIPconsGetData(cons);
14148  assert(consdata != NULL);
14149 
14150  nvars = consdata->nvars;
14151 
14152  SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
14153  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
14154 
14155  /* create opening of the GML format */
14156  SCIPgmlWriteOpening(file, TRUE);
14157 
14158  for( v = 0; v < nvars; ++v )
14159  {
14160  char color[SCIP_MAXSTRLEN];
14161 
14162  var = consdata->vars[v];
14163  assert(var != NULL);
14164 
14165  SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
14166 
14167  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14168  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14169  else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14170  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14171  else
14172  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14173 
14174  SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14175  }
14176 
14177  for( v = 0; v < nvars; ++v )
14178  {
14179  SCIP_VAR** vbdvars;
14180  int nvbdvars;
14181  int b;
14182 
14183  var = consdata->vars[v];
14184  assert(var != NULL);
14185 
14186  vbdvars = SCIPvarGetVlbVars(var);
14187  nvbdvars = SCIPvarGetNVlbs(var);
14188 
14189  for( b = 0; b < nvbdvars; ++b )
14190  {
14191  if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14192  {
14193  SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14194  }
14195  }
14196 
14197 #if 0
14198  vbdvars = SCIPvarGetVubVars(var);
14199  nvbdvars = SCIPvarGetNVubs(var);
14200 
14201  for( b = 0; b < nvbdvars; ++b )
14202  {
14203  if( SCIPhashtableExists(vars, vbdvars[b]) )
14204  {
14205  SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14206  }
14207  }
14208 #endif
14209  }
14210 
14211  /* create closing of the GML format */
14212  SCIPgmlWriteClosing(file);
14213  /* cppcheck-suppress unusedLabel */
14214 TERMINATE:
14215  /* close file */
14216  fclose(file);
14217 
14218  SCIPhashtableFree(&vars);
14219 
14220  return retcode;
14221 }
14222 
14223 /** sets method to solve an individual cumulative condition */
14225  SCIP* scip, /**< SCIP data structure */
14226  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14227  )
14228 {
14229  SCIP_CONSHDLR* conshdlr;
14230  SCIP_CONSHDLRDATA* conshdlrdata;
14231 
14232  /* find the cumulative constraint handler */
14233  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14234  if( conshdlr == NULL )
14235  {
14236  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14237  return SCIP_PLUGINNOTFOUND;
14238  }
14239 
14240  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14241  assert(conshdlrdata != NULL);
14242 
14243  conshdlrdata->solveCumulative = solveCumulative;
14244 
14245  return SCIP_OKAY;
14246 }
14247 
14248 /** solves given cumulative condition as independent sub problem
14249  *
14250  * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14251  * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14252  * solver was interrupted.
14253  */
14255  SCIP* scip, /**< SCIP data structure */
14256  int njobs, /**< number of jobs (activities) */
14257  SCIP_Real* ests, /**< array with the earlier start time for each job */
14258  SCIP_Real* lsts, /**< array with the latest start time for each job */
14259  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14260  int* durations, /**< array of durations */
14261  int* demands, /**< array of demands */
14262  int capacity, /**< cumulative capacity */
14263  int hmin, /**< left bound of time axis to be considered (including hmin) */
14264  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14265  SCIP_Real timelimit, /**< time limit for solving in seconds */
14266  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14267  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14268  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14269  SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14270  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14271  SCIP_Bool* error /**< pointer to store if an error occurred */
14272  )
14273 {
14274  SCIP_CONSHDLR* conshdlr;
14275  SCIP_CONSHDLRDATA* conshdlrdata;
14276 
14277  (*solved) = TRUE;
14278  (*infeasible) = FALSE;
14279  (*unbounded) = FALSE;
14280  (*error) = FALSE;
14281 
14282  if( njobs == 0 )
14283  return SCIP_OKAY;
14284 
14285  /* find the cumulative constraint handler */
14286  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14287  if( conshdlr == NULL )
14288  {
14289  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14290  (*error) = TRUE;
14291  return SCIP_PLUGINNOTFOUND;
14292  }
14293 
14294  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14295  assert(conshdlrdata != NULL);
14296 
14297  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14298  if( timelimit > 0.0 && memorylimit > 10 )
14299  {
14300  SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14301  hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14302  }
14303 
14304  return SCIP_OKAY;
14305 }
14306 
14307 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14308  * completion time
14309  */
14311  SCIP* scip, /**< SCIP data structure */
14312  SCIP_PROFILE* profile, /**< resource profile */
14313  int nvars, /**< number of variables (jobs) */
14314  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14315  int* durations, /**< array containing corresponding durations */
14316  int* demands /**< array containing corresponding demands */
14317  )
14318 {
14319  SCIP_VAR* var;
14320  SCIP_HASHMAP* addedvars;
14321  int* copydemands;
14322  int* perm;
14323  int duration;
14324  int impliedest;
14325  int est;
14326  int impliedlct;
14327  int lct;
14328  int v;
14329 
14330  /* create hash map for variables which are added, mapping to their duration */
14331  SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
14332 
14333  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14334  SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14335 
14336  /* sort variables w.r.t. job demands */
14337  for( v = 0; v < nvars; ++v )
14338  {
14339  copydemands[v] = demands[v];
14340  perm[v] = v;
14341  }
14342  SCIPsortDownIntInt(copydemands, perm, nvars);
14343 
14344  /* add each job with its earliest start and latest completion time into the resource profile */
14345  for( v = 0; v < nvars; ++v )
14346  {
14347  int idx;
14348 
14349  idx = perm[v];
14350  assert(idx >= 0 && idx < nvars);
14351 
14352  var = vars[idx];
14353  assert(var != NULL);
14354 
14355  duration = durations[idx];
14356  assert(duration > 0);
14357 
14358  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
14359  SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14360 
14361  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14362  SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14363 
14364  if( impliedest < impliedlct )
14365  {
14366  SCIP_Bool infeasible;
14367  int pos;
14368 
14369  SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14370  assert(!infeasible);
14371  assert(pos == -1);
14372  }
14373 
14374  if( est == impliedest && lct == impliedlct )
14375  {
14376  SCIP_CALL( SCIPhashmapInsert(addedvars, (void*)var, (void*)(size_t)duration) );
14377  }
14378  }
14379 
14380  SCIPfreeBufferArray(scip, &copydemands);
14381  SCIPfreeBufferArray(scip, &perm);
14382 
14383  SCIPhashmapFree(&addedvars);
14384 
14385  return SCIP_OKAY;
14386 }
14387 
14388 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */
14389 int SCIPcomputeHmin(
14390  SCIP* scip, /**< SCIP data structure */
14391  SCIP_PROFILE* profile, /**< worst case resource profile */
14392  int capacity /**< capacity to check */
14393  )
14394 {
14395  int* timepoints;
14396  int* loads;
14397  int ntimepoints;
14398  int t;
14399 
14400  ntimepoints = SCIPprofileGetNTimepoints(profile);
14401  timepoints = SCIPprofileGetTimepoints(profile);
14402  loads = SCIPprofileGetLoads(profile);
14403 
14404  /* find first time point which potentially violates the capacity restriction */
14405  for( t = 0; t < ntimepoints - 1; ++t )
14406  {
14407  /* check if the time point exceed w.r.t. worst case profile the capacity */
14408  if( loads[t] > capacity )
14409  {
14410  assert(t == 0 || loads[t-1] <= capacity);
14411  return timepoints[t];
14412  }
14413  }
14414 
14415  return INT_MAX;
14416 }
14417 
14418 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity is satisfied for sure */
14419 int SCIPcomputeHmax(
14420  SCIP* scip, /**< SCIP data structure */
14421  SCIP_PROFILE* profile, /**< worst case profile */
14422  int capacity /**< capacity to check */
14423  )
14424 {
14425  int* timepoints;
14426  int* loads;
14427  int ntimepoints;
14428  int t;
14429 
14430  ntimepoints = SCIPprofileGetNTimepoints(profile);
14431  timepoints = SCIPprofileGetTimepoints(profile);
14432  loads = SCIPprofileGetLoads(profile);
14433 
14434  /* find last time point which potentially violates the capacity restriction */
14435  for( t = ntimepoints - 1; t >= 0; --t )
14436  {
14437  /* check if at time point t the worst case resource profile exceeds the capacity */
14438  if( loads[t] > capacity )
14439  {
14440  assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14441  return timepoints[t+1];
14442  }
14443  }
14444 
14445  return INT_MIN;
14446 }
14447 
14448 /**@} */
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
static SCIP_RETCODE consdataCatchEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_RETCODE SCIPbtnodeCreate(SCIP_BT *tree, SCIP_BTNODE **node, void *dataptr)
Definition: misc.c:7501
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:21909
#define CONSHDLR_SEPAPRIORITY
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4143
int SCIPgetNCheckConss(SCIP *scip)
Definition: scip.c:12821
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:21898
void SCIPbtnodeFree(SCIP_BT *tree, SCIP_BTNODE **node)
Definition: misc.c:7565
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:6228
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip.c:40508
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip.c:45137
static SCIP_RETCODE propagateAllConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *nfixedvars, SCIP_Bool *cutoff, SCIP_Bool *branched)
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17380
static SCIP_DECL_CONSCOPY(consCopyCumulative)
enum TCLIQUE_Status TCLIQUE_STATUS
Definition: tclique.h:57
static TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
#define DEFAULT_TTINFER
#define CONSHDLR_PROPFREQ
static int computeEnergyContribution(SCIP_BTNODE *node)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:21892
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
static SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22118
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30233
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip.c:19263
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46086
SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_setppc.c:9149
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:814
static SCIP_RETCODE consdataDropAllEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static PROPRULE inferInfoGetProprule(INFERINFO inferinfo)
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8140
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:6251
static SCIP_RETCODE checkCumulativeCondition(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *violated, SCIP_CONS *cons, SCIP_Bool printreason)
constraint handler for cumulative constraints
static SCIP_RETCODE propagateEdgeFinding(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPprofileDeleteCore(SCIP_PROFILE *profile, int left, int right, int demand)
Definition: misc.c:6115
static SCIP_RETCODE computeMinDistance(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int source, int sink, int *naddconss)
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip.c:19123
void * SCIPbtnodeGetData(SCIP_BTNODE *node)
Definition: misc.c:7610
SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
Definition: scip.c:36778
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2254
struct TCLIQUE_Graph TCLIQUE_GRAPH
Definition: tclique.h:38
static INFERINFO intToInferInfo(int i)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:40275
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:6541
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30256
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17358
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)
static SCIP_RETCODE createCapacityRestrictionIntvars(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17166
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:6481
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip.c:4426
static void addEndingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *endtimes, int *endindices, int *freecapacity, int *idx, int nvars)
#define SCIP_MAXSTRLEN
Definition: def.h:215
#define DEFAULT_MAXNODES
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:16753
void SCIPgmlWriteArc(FILE *file, unsigned int source, unsigned int target, const char *label, const char *color)
Definition: misc.c:627
SCIP_RETCODE SCIPincludeConshdlrCumulative(SCIP *scip)
SCIP_RETCODE SCIPcreateConsBasicCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity)
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip.c:5973
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:27962
SCIP_RETCODE SCIPnormalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
int SCIPgetHminCumulative(SCIP *scip, SCIP_CONS *cons)
static int computeOverlap(int begin, int end, int est, int lst, int duration)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12481
static SCIP_RETCODE constraintNonOverlappingGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:45601
static long bound
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:30288
static SCIP_RETCODE analyzeEnergyRequirement(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int begin, int end, SCIP_VAR *infervar, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation)
static void initializeLocks(SCIP_CONSDATA *consdata, SCIP_Bool locked)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:45876
#define CONSHDLR_NAME
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17222
SCIP_VAR ** SCIPgetVarsCumulative(SCIP *scip, SCIP_CONS *cons)
#define CONSHDLR_PROP_TIMING
int * SCIPgetValsLinking(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45803
static SCIP_RETCODE createDisjuctiveCons(SCIP *scip, SCIP_CONS *cons, int *naddconss)
#define CONSHDLR_CHECKPRIORITY
static int inferInfoGetData1(INFERINFO inferinfo)
static SCIP_RETCODE solveIndependentCons(SCIP *scip, SCIP_CONS *cons, SCIP_Longint maxnodes, int *nchgbds, int *nfixedvars, int *ndelconss, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:8526
static void updateKeyOnTrace(SCIP_BTNODE *node, SCIP_Real key)
void SCIPgmlWriteNode(FILE *file, unsigned int id, const char *label, const char *nodetype, const char *fillcolor, const char *bordercolor)
Definition: misc.c:485
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip.c:27674
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip.c:17656
static SCIP_RETCODE presolveConsEst(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
int SCIPprofileGetTime(SCIP_PROFILE *profile, int pos)
Definition: misc.c:5912
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:18384
static SCIP_RETCODE computePeak(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *timepoint)
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip.c:6142
static void transitiveClosure(SCIP_Bool **adjmatrix, int *ninarcs, int *noutarcs, int nnodes)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:46175
void SCIPgmlWriteClosing(FILE *file)
Definition: misc.c:687
SCIP_RETCODE SCIPtransformConss(SCIP *scip, int nconss, SCIP_CONS **conss, SCIP_CONS **transconss)
Definition: scip.c:27775
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:8996
void SCIPbtnodeSetRightchild(SCIP_BTNODE *node, SCIP_BTNODE *right)
Definition: misc.c:7771
static SCIP_Bool isConsIndependently(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE applyAlternativeBoundsFixing(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, int *nfixedvars, SCIP_Bool *cutoff)
static SCIP_DECL_SORTPTRCOMP(compNodeEst)
#define FALSE
Definition: def.h:64
static SCIP_RETCODE collectIntVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***activevars, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower, int *lhs)
static SCIP_RETCODE fixIntegerVariableLb(SCIP *scip, SCIP_VAR *var, SCIP_Bool downlock, int *nfixedvars)
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2765
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:278
SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4230
static SCIP_RETCODE consdataFreeRows(SCIP *scip, SCIP_CONSDATA **consdata)
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip.c:5831
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:45816
static SCIP_RETCODE checkOverloadViaThetaTree(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool propest, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:9340
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:45888
#define TRUE
Definition: def.h:63
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:27036
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
enum Proprule PROPRULE
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
Definition: scip.c:26813
static void subtractStartingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *starttimes, int *startindices, int *freecapacity, int *idx, int nvars)
SCIP_Bool SCIPexistsConsLinking(SCIP *scip, SCIP_VAR *intvar)
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:21255
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8160
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17400
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
static SCIP_RETCODE presolveConsEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff)
static SCIP_RETCODE removeIrrelevantJobs(SCIP *scip, SCIP_CONS *cons)
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:16859
static SCIP_RETCODE applyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_Real leftub, SCIP_Real rightlb, SCIP_Real *leftimpllbs, SCIP_Real *leftimplubs, SCIP_Real *leftproplbs, SCIP_Real *leftpropubs, SCIP_Real *rightimpllbs, SCIP_Real *rightimplubs, SCIP_Real *rightproplbs, SCIP_Real *rightpropubs, int *nfixedvars, SCIP_Bool *success, SCIP_Bool *cutoff)
static SCIP_RETCODE presolveCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nfixedvars, int *nchgbds, int *ndelconss, int *naddconss, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition: scip.c:17317
static SCIP_RETCODE strengthenVarbounds(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *naddconss)
static SCIP_RETCODE getNodeIdx(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_VAR *var, int *idx)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8190
static void conshdlrdataFree(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata)
void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
Definition: scip.c:26780
#define DEFAULT_LOCALCUTS
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
Definition: scip.c:26717
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22234
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:21907
static SCIP_RETCODE deleteLambdaLeaf(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
SCIP_RETCODE SCIPprofileInsertCore(SCIP_PROFILE *profile, int left, int right, int demand, int *pos, SCIP_Bool *infeasible)
Definition: misc.c:6085
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip.c:5885
#define CONSHDLR_DELAYPROP
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17370
static SCIP_RETCODE separateCoverCutsCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
#define DEFAULT_USEBINVARS
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip.c:1228
static TCLIQUE_ISEDGE(tcliqueIsedgeClique)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip.h:21933
tclique user interface
static SCIP_RETCODE createCoreProfile(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2903
#define DEFAULT_COEFTIGHTENING
static SCIP_RETCODE createNodedata(SCIP *scip, SCIP_NODEDATA **nodedata)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45751
SCIP_RETCODE SCIPaddVarVlb(SCIP *scip, SCIP_VAR *var, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconstant, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip.c:23568
#define SCIP_LONGINT_MAX
Definition: def.h:121
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:21937
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip.c:696
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:16763
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:21890
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip.c:1010
#define DEFAULT_TTEFCHECK
static void createSelectedSortedEventpointsSol(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *starttimes, int *endtimes, int *startindices, int *endindices, int *nvars, SCIP_Bool lower)
static SCIP_DECL_CONSINITLP(consInitlpCumulative)
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition: scip.c:4741
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8150
SCIP_RETCODE SCIPsetHmaxCumulative(SCIP *scip, SCIP_CONS *cons, int hmax)
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:6274
#define SCIPdebugMsgPrint
Definition: scip.h:452
int SCIPprofileGetLoad(SCIP_PROFILE *profile, int pos)
Definition: misc.c:5924
#define SCIPdebugMsg
Definition: scip.h:451
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip.c:18616
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:6458
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:7942
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1336
static SCIP_DECL_CONSPRESOL(consPresolCumulative)
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip.c:27146
SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
Definition: scip.c:9839
#define DEFAULT_NORMALIZE
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
Definition: scip.c:26746
static SCIP_RETCODE deleteTrivilCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, SCIP_Bool *cutoff)
SCIP_Bool SCIPbtnodeIsRoot(SCIP_BTNODE *node)
Definition: misc.c:7670
static SCIP_RETCODE respropCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, INFERINFO inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation, SCIP_RESULT *result)
static SCIP_RETCODE removeOversizedJobs(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *nchgcoefs, int *naddconss, SCIP_Bool *cutoff)
static SCIP_RETCODE createConsCumulative(SCIP *scip, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
Definition: scip.c:46223
enum Proprule PROPRULE
static SCIP_RETCODE adjustOversizedJobBounds(SCIP *scip, SCIP_CONSDATA *consdata, int pos, int *nchgbds, int *naddconss, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:2015
static SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
static SCIP_RETCODE coretimesUpdateUb(SCIP *scip, SCIP_VAR *var, int duration, int demand, int capacity, SCIP_CONS *cons, SCIP_PROFILE *profile, int idx, int *nchgbds)
SCIP_RETCODE SCIPcreateConsVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static void freeTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
#define CONSHDLR_DESC
static void createSortedEventpointsSol(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices)
int SCIPgetNVarsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE conshdlrdataCreate(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:16522
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2997
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
Definition: scip.c:26695
SCIP_RETCODE SCIPsplitCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
static SCIP_RETCODE enforceSolution(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool branch, SCIP_RESULT *result)
static SCIP_RETCODE updateEnvelop(SCIP *scip, SCIP_BTNODE *node)
static SCIP_RETCODE separateConsBinaryRepresentation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip.c:27446
static SCIP_RETCODE findPrecedenceConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
static SCIP_DECL_CONSCHECK(consCheckCumulative)
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17176
static SCIP_RETCODE getHighestCapacityUsage(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, int *bestcapacity)
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:21904
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_VAR **vars, SCIP_CONS **linkingconss, int *durations, int *demands, int nvars, int capacity, int hmin, int hmax, SCIP_Bool check)
Constraint handler for knapsack constraints of the form , x binary and .
static const NodeData nodedata[]
Definition: gastrans.c:74
int SCIPcomputeHmin(SCIP *scip, SCIP_PROFILE *profile, int capacity)
#define CONSHDLR_EAGERFREQ
#define CONSHDLR_PRESOLTIMING
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip.c:15777
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:5997
static SCIP_RETCODE collectBranchingCands(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nbranchcands)
#define CONSHDLR_DELAYSEPA
static SCIP_RETCODE findCumulativeConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
static int inferInfoGetData2(INFERINFO inferinfo)
#define EVENTHDLR_NAME
static SCIP_RETCODE propagateTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_DECL_CONSLOCK(consLockCumulative)
SCIP_BTNODE * SCIPbtnodeGetParent(SCIP_BTNODE *node)
Definition: misc.c:7620
static SCIP_RETCODE tightenUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int lst, int lct, int begin, int end, int energy, int *bestub, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
#define SCIPerrorMessage
Definition: pub_message.h:45
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4113
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12410
static SCIP_RETCODE projectVbd(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph)
static SCIP_RETCODE createTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_RETCODE SCIPsolveCumulative(SCIP *scip, int njobs, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Real *objvals, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Longint maxnodes, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *error)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45764
void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:13111
void SCIPbtnodeSetLeftchild(SCIP_BTNODE *node, SCIP_BTNODE *left)
Definition: misc.c:7757
static SCIP_RETCODE collectBinaryVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***vars, int **coefs, int *nvars, int *startindices, int curtime, int nstarted, int nfinished)
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
#define SCIPallocBuffer(scip, ptr)
Definition: scip.h:21923
int SCIPgetHmaxCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip.c:18929
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip.h:21938
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition: scip.c:4567
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip.c:921
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:45519
SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:27012
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
void SCIPstrCopySection(const char *str, char startchar, char endchar, char *token, int size, char **endptr)
Definition: misc.c:9441
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21383
static void traceLambdaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
static SCIP_RETCODE computeEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss, int *nchgsides)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:7881
static int computeEstOmegaset(SCIP *scip, int duration, int demand, int capacity, int est, int lct, int energy)
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17432
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:25494
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8100
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:155
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16552
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:6022
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2798
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4133
static SCIP_RETCODE propagateCumulativeCondition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *redundant, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
#define NULL
Definition: lpi_spx1.cpp:137
static TCLIQUE_NEWSOL(tcliqueNewsolClique)
static SCIP_RETCODE coretimesUpdateLb(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_PROFILE *profile, int idx, int *nchgbds, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *infeasible)
static SCIP_RETCODE createCumulativeCons(SCIP *scip, const char *name, TCLIQUE_GRAPH *tcliquegraph, int *cliquenodes, int ncliquenodes)
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
void tcliqueMaxClique(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, TCLIQUE_WEIGHT maxfirstnodeweight, TCLIQUE_WEIGHT minweight, int maxntreenodes, int backtrackfreq, int maxnzeroextensions, int fixednode, int *ntreenodes, TCLIQUE_STATUS *status)
#define CONSHDLR_MAXPREROUNDS
static SCIP_RETCODE createCoverCuts(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss, SCIP_Bool *infeasible)
static int computeTotalEnergy(int *durations, int *demands, int njobs)
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_CALL(x)
Definition: def.h:306
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17390
static SCIP_RETCODE propagateLbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, int *newlbs, int *newubs, int *lbinferinfos, int *ubinferinfos, int *ects, int *flexenergies, int *perm, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
void SCIPsortDownIntIntInt(int *intarray1, int *intarray2, int *intarray3, int len)
#define SCIPstatisticPrintf
Definition: pub_message.h:107
SCIP_RETCODE SCIPsetEmphasis(SCIP *scip, SCIP_PARAMEMPHASIS paramemphasis, SCIP_Bool quiet)
Definition: scip.c:4998
static TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
Definition: scip.c:27097
SCIP_RETCODE SCIPprofileCreate(SCIP_PROFILE **profile, int capacity)
Definition: misc.c:5812
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17422
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8120
#define DEFAULT_PRESOLPAIRWISE
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:27288
#define DEFAULT_DETECTDISJUNCTIVE
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip.c:6297
static SCIP_DECL_CONSFREE(consFreeCumulative)
SCIP_Bool SCIPbtnodeIsRightchild(SCIP_BTNODE *node)
Definition: misc.c:7708
SCIP_RETCODE SCIPaddCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:33869
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:50
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:106
static SCIP_RETCODE consCapacityConstraintsFinder(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
SCIP_BTNODE * SCIPbtGetRoot(SCIP_BT *tree)
Definition: misc.c:7893
static void collectDataTTEF(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int hmin, int hmax, int *permests, int *ests, int *permlcts, int *lcts, int *ects, int *lsts, int *flexenergies)
static SCIP_RETCODE consCheckRedundancy(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *redundant)
constraint handler for linking binary variables to an integer variable
SCIP_BTNODE * SCIPbtnodeGetRightchild(SCIP_BTNODE *node)
Definition: misc.c:7640
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:21925
#define SCIP_UNKNOWN
Definition: def.h:156
static SCIP_RETCODE propagateUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, int *newlbs, int *newubs, int *lbinferinfos, int *ubinferinfos, int *lsts, int *flexenergies, int *perm, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static void traceThetaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
#define SCIP_Bool
Definition: def.h:61
static SCIP_RETCODE presolveConsLct(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPincludeDefaultPlugins(SCIP *scip)
static SCIP_RETCODE consdataDropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos)
static SCIP_DECL_CONSPROP(consPropCumulative)
#define DEFAULT_DUALPRESOLVE
static SCIP_RETCODE analyseInfeasibelCoreInsertion(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferduration, int inferdemand, int inferpeak, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation)
#define DEFAULT_USEADJUSTEDJOBS
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nchgbds, int *ndelconss, SCIP_Bool *cutoff)
void SCIPprintSysError(const char *message)
Definition: misc.c:9276
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:30022
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:42094
#define DEFAULT_USECOVERCUTS
static void freeNodedata(SCIP *scip, SCIP_NODEDATA **nodedata)
SCIP_Bool SCIPprofileFindLeft(SCIP_PROFILE *profile, int timepoint, int *pos)
Definition: misc.c:5938
static SCIP_DECL_EVENTEXEC(eventExecCumulative)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:28652
int SCIPvarGetNLocksUp(SCIP_VAR *var)
Definition: var.c:3217
#define SCIP_DECL_CONSEXITPRE(x)
Definition: type_cons.h:138
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:9411
static SCIP_RETCODE normalizeDemands(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
static SCIP_RETCODE computeCoreEngeryAfter(SCIP *scip, SCIP_PROFILE *profile, int nvars, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct)
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:7901
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11249
SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
Definition: scip.c:26848
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip.c:4625
void SCIPbtFree(SCIP_BT **tree)
Definition: misc.c:7801
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8010
SCIP_RETCODE SCIPcheckCumulativeCondition(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *violated, SCIP_CONS *cons, SCIP_Bool printreason)
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
SCIP_Bool SCIPbtnodeIsLeftchild(SCIP_BTNODE *node)
Definition: misc.c:7690
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8080
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8050
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17014
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:40321
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip.c:17237
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip.c:36399
#define SCIP_PRESOLTIMING_ALWAYS
Definition: type_timing.h:49
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip.c:25141
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:89
static SCIP_RETCODE branch(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_Bool allowaddcons, SCIP_RESULT *result)
int SCIPgetNRuns(SCIP *scip)
Definition: scip.c:41099
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21309
void SCIPprofilePrint(SCIP_PROFILE *profile, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: misc.c:5850
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip.c:6435
int * SCIPgetDurationsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE inferboundsEdgeFinding(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS *cons, SCIP_BT *tree, SCIP_BTNODE **leaves, int capacity, int ncands, SCIP_Bool propest, int shift, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
static SCIP_RETCODE consdataDeletePos(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_CONS *cons, int pos)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:45827
#define CONSHDLR_NEEDSCONS
int * SCIPprofileGetTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:5892
int SCIPconvertRealToInt(SCIP *scip, SCIP_Real real)
Definition: scip.c:46594
static SCIP_RETCODE computeImpliedEst(SCIP *scip, SCIP_VAR *var, SCIP_HASHMAP *addedvars, int *est)
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22414
static SCIP_RETCODE tightenCoefs(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs)
static SCIP_DECL_SORTINDCOMP(consdataCompVar)
Proprule
#define DEFAULT_FILLBRANCHCANDS
static SCIP_Bool checkDemands(SCIP *scip, SCIP_CONS *cons)
int * SCIPprofileGetLoads(SCIP_PROFILE *profile)
Definition: misc.c:5902
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:35033
SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
Definition: scip.c:4799
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2065
SCIP_Bool SCIPbtIsEmpty(SCIP_BT *tree)
Definition: misc.c:7883
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:11631
#define DEFAULT_DETECTVARBOUNDS
SCIP_RETCODE SCIPrespropCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool *explanation, SCIP_RESULT *result)
static SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
SCIP_BTNODE * SCIPbtnodeGetLeftchild(SCIP_BTNODE *node)
Definition: misc.c:7630
SCIP_RETCODE SCIPpresolveCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
static SCIP_RETCODE tightenLbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int ect, int lct, int begin, int end, int energy, int *bestlb, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static void createSortedEventpoints(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices, SCIP_Bool local)
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:6166
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:30160
void SCIPbtSetRoot(SCIP_BT *tree, SCIP_BTNODE *root)
Definition: misc.c:7906
SCIP_RETCODE SCIPsetHminCumulative(SCIP *scip, SCIP_CONS *cons, int hmin)
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3013
SCIP_RETCODE SCIPcreateConsLinking(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *intvar, SCIP_VAR **binvars, int *vals, int nbinvars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define SCIPfreeBuffer(scip, ptr)
Definition: scip.h:21935
static SCIP_RETCODE insertThetanode(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node, SCIP_NODEDATA **nodedatas, int *nnodedatas)
SCIP_RETCODE SCIPapplyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_BOUNDTYPE boundtype, SCIP_Real bound, int maxproprounds, SCIP_Real *impllbs, SCIP_Real *implubs, SCIP_Real *proplbs, SCIP_Real *propubs, SCIP_Bool *cutoff)
#define CONSHDLR_SEPAFREQ
int SCIPgetCapacityCumulative(SCIP *scip, SCIP_CONS *cons)
void SCIPbtnodeSetParent(SCIP_BTNODE *node, SCIP_BTNODE *parent)
Definition: misc.c:7743
static SCIP_RETCODE removeRedundantConss(SCIP *scip, SCIP_CONS **conss, int nconss, int *ndelconss)
static SCIP_RETCODE getActiveVar(SCIP *scip, SCIP_VAR **var, int *scalar, int *constant)
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3162
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:4653
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip.c:38931
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45790
static SCIP_RETCODE computeAlternativeBounds(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks)
static void traceLambdaEnergy(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
SCIP_Longint SCIPgetMemUsed(SCIP *scip)
Definition: scip.c:45562
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip.c:1911
static SCIP_DECL_CONSPRINT(consPrintCumulative)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:11311
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:7911
SCIP_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22527
static SCIP_RETCODE consdataCollectLinkingCons(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip.c:16968
static SCIP_RETCODE initializeDurations(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
SCIP_RETCODE SCIPgetBinvarsLinking(SCIP *scip, SCIP_CONS *cons, SCIP_VAR ***binvars, int *nbinvars)
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip.c:27471
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnvelop(SCIP_BTNODE *node)
int SCIPgetNConss(SCIP *scip)
Definition: scip.c:12679
static SCIP_RETCODE constructIncompatibilityGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE moveNodeToLambda(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:27323
#define DEFAULT_CUTSASCONSS
static int computeCoreWithInterval(int begin, int end, int ect, int lst)
static void collectThetaSubtree(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
SCIP_Bool SCIPallowDualReds(SCIP *scip)
Definition: scip.c:25447
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:6190
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30579
static SCIP_RETCODE resolvePropagationCoretimes(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferdemand, int inferpeak, int relaxedpeak, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool usebdwidening, int *provedpeak, SCIP_Bool *explanation)
SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
Definition: scip.c:45588
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip.c:11586
static SCIP_RETCODE normalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16671
SCIP_RETCODE SCIPcreateWorstCaseProfile(SCIP *scip, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands)
#define SCIPstatistic(x)
Definition: pub_message.h:101
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition: scip.c:25250
int * SCIPgetDemandsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
#define SCIP_Real
Definition: def.h:135
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8130
static SCIP_RETCODE applyAlternativeBoundsBranching(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, SCIP_Bool *branched)
static SCIP_DECL_CONSPARSE(consParseCumulative)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1138
static SCIP_DECL_CONSTRANS(consTransCumulative)
#define MIN(x, y)
Definition: memory.c:75
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:6504
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:327
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
static SCIP_RETCODE fixIntegerVariableUb(SCIP *scip, SCIP_VAR *var, SCIP_Bool uplock, int *nfixedvars)
#define DEFAULT_EFCHECK
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8070
#define SCIP_INVALID
Definition: def.h:155
#define EVENTHDLR_DESC
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8060
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:30762
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17412
#define DEFAULT_TTEFINFER
void SCIPsortInt(int *intarray, int len)
static SCIP_RETCODE createPrecedenceCons(SCIP *scip, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, int distance)
static INFERINFO getInferInfo(PROPRULE proprule, int data1, int data2)
#define SCIP_Longint
Definition: def.h:120
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:16849
static SCIP_RETCODE detectRedundantConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, int *naddconss)
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip.c:30736
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16717
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2366
static SCIP_RETCODE varMayRoundUp(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:45864
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45777
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:49
static SCIP_RETCODE separateConsOnIntegerVariables(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool lower, SCIP_Bool *separated)
SCIP_RETCODE SCIPcreateConsCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static void consdataCalcSignature(SCIP_CONSDATA *consdata)
#define DEFAULT_EFINFER
#define nnodes
Definition: gastrans.c:65
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17232
static SCIP_RETCODE createCapacityRestriction(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool cutsasconss)
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:21910
void SCIPgmlWriteOpening(FILE *file, SCIP_Bool directed)
Definition: misc.c:671
SCIP_RETCODE SCIPpropCumulativeCondition(SCIP *scip, SCIP_PRESOLTIMING presoltiming, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:46187
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16694
static SCIP_Bool impliesVlbPrecedenceCondition(SCIP *scip, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconst, int duration)
#define DEFAULT_DISJUNCTIVE
SCIP_CONS * SCIPgetConsLinking(SCIP *scip, SCIP_VAR *intvar)
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2846
int SCIPcomputeHmax(SCIP *scip, SCIP_PROFILE *profile, int capacity)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:85
#define DEFAULT_USEBDWIDENING
static SCIP_RETCODE tightenCapacity(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
SCIP_RETCODE SCIPcreateConsBasicSetpart(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
Definition: cons_setppc.c:9016
void SCIPswapInts(int *value1, int *value2)
Definition: misc.c:8970
SCIP_RETCODE SCIPbtCreate(SCIP_BT **tree, BMS_BLKMEM *blkmem)
Definition: misc.c:7782
static SCIP_RETCODE collectDemands(SCIP *scip, SCIP_CONSDATA *consdata, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Longint **demands, int *ndemands)
static SCIP_RETCODE computeEffectiveHorizonCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
int TCLIQUE_WEIGHT
Definition: tclique.h:37
static SCIP_DECL_CONSINITPRE(consInitpreCumulative)
static SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
static SCIP_RETCODE computeImpliedLct(SCIP *scip, SCIP_VAR *var, int duration, SCIP_HASHMAP *addedvars, int *lct)
int SCIPprofileGetNTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:5882
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:6118
#define SCIPABORT()
Definition: def.h:278
static SCIP_DECL_CONSDELETE(consDeleteCumulative)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:7945
SCIP_RETCODE SCIPvisualizeConsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:38007
default SCIP plugins
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnergy(SCIP_BTNODE *node)
static SCIP_DECL_CONSSEPALP(consSepalpCumulative)
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *violated, SCIP_Bool printreason)
SCIP_RETCODE SCIPsetSubscipsOff(SCIP *scip, SCIP_Bool quiet)
Definition: scip.c:5020
SCIP_Bool SCIPbtnodeIsLeaf(SCIP_BTNODE *node)
Definition: misc.c:7680
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip.c:4683
static int inferInfoToInt(INFERINFO inferinfo)
static TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4176
SCIP_RETCODE SCIPsetSolveCumulative(SCIP *scip, SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)))
static SCIP_DECL_CONSRESPROP(consRespropCumulative)
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16839
static SCIP_RETCODE varMayRoundDown(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
void SCIPprofileFree(SCIP_PROFILE **profile)
Definition: misc.c:5836
#define CONSHDLR_ENFOPRIORITY
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip.c:774
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:21929
static SCIP_Bool impliesVubPrecedenceCondition(SCIP *scip, SCIP_VAR *var, SCIP_Real vubcoef, SCIP_Real vubconst, int duration)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip.c:5931
#define DEFAULT_SEPAOLD
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip.c:27421