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-2020 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_cumulative.c
17  * @ingroup DEFPLUGINS_CONS
18  * @brief constraint handler for cumulative constraints
19  * @author Timo Berthold
20  * @author Stefan Heinz
21  * @author Jens Schulz
22  *
23  * Given:
24  * - 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
25  * their demands \f$d_j\f$.
26  * - an integer resource capacity \f$C\f$
27  *
28  * 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.
29  *
30  * Separation:
31  * - can be done using binary start time model, see Pritskers, Watters and Wolfe
32  * - or by just separating relatively weak cuts on the integer start time variables
33  *
34  * Propagation:
35  * - time tabling, Klein & Scholl (1999)
36  * - Edge-finding from Petr Vilim, adjusted and simplified for dynamic repropagation
37  * (2009)
38  * - energetic reasoning, see Baptiste, Le Pape, Nuijten (2001)
39  *
40  */
41 
42 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
43 
44 #include <assert.h>
45 #include <string.h>
46 
47 #include "tclique/tclique.h"
48 #include "scip/cons_cumulative.h"
49 #include "scip/cons_linking.h"
50 #include "scip/cons_knapsack.h"
51 #include "scip/scipdefplugins.h"
52 
53 /**@name Constraint handler properties
54  *
55  * @{
56  */
57 
58 /* constraint handler properties */
59 #define CONSHDLR_NAME "cumulative"
60 #define CONSHDLR_DESC "cumulative constraint handler"
61 #define CONSHDLR_SEPAPRIORITY 2100000 /**< priority of the constraint handler for separation */
62 #define CONSHDLR_ENFOPRIORITY -2040000 /**< priority of the constraint handler for constraint enforcing */
63 #define CONSHDLR_CHECKPRIORITY -3030000 /**< priority of the constraint handler for checking feasibility */
64 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
65 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
66 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
67  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
68 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
69 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
70 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
71 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
72 
73 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
74 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
75 
76 /**@} */
77 
78 /**@name Default parameter values
79  *
80  * @{
81  */
82 
83 /* default parameter values */
84 
85 /* separation */
86 #define DEFAULT_USEBINVARS FALSE /**< should the binary representation be used? */
87 #define DEFAULT_LOCALCUTS FALSE /**< should cuts be added only locally? */
88 #define DEFAULT_USECOVERCUTS TRUE /**< should covering cuts be added? */
89 #define DEFAULT_CUTSASCONSS TRUE /**< should the cuts be created as knapsack constraints? */
90 #define DEFAULT_SEPAOLD TRUE /**< shall old sepa algo be applied? */
91 
92 /* propagation */
93 #define DEFAULT_TTINFER TRUE /**< should time-table (core-times) propagator be used to infer bounds? */
94 #define DEFAULT_EFCHECK FALSE /**< should edge-finding be used to detect an overload? */
95 #define DEFAULT_EFINFER FALSE /**< should edge-finding be used to infer bounds? */
96 #define DEFAULT_USEADJUSTEDJOBS FALSE /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
97 #define DEFAULT_TTEFCHECK TRUE /**< should time-table edge-finding be used to detect an overload? */
98 #define DEFAULT_TTEFINFER TRUE /**< should time-table edge-finding be used to infer bounds? */
99 
100 /* presolving */
101 #define DEFAULT_DUALPRESOLVE TRUE /**< should dual presolving be applied? */
102 #define DEFAULT_COEFTIGHTENING FALSE /**< should coeffisient tightening be applied? */
103 #define DEFAULT_NORMALIZE TRUE /**< should demands and capacity be normalized? */
104 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
105 #define DEFAULT_DISJUNCTIVE TRUE /**< extract disjunctive constraints? */
106 #define DEFAULT_DETECTDISJUNCTIVE TRUE /**< search for conflict set via maximal cliques to detect disjunctive constraints */
107 #define DEFAULT_DETECTVARBOUNDS TRUE /**< search for conflict set via maximal cliques to detect variable bound constraints */
108 #define DEFAULT_MAXNODES 10000LL /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
110 /* enforcement */
111 #define DEFAULT_FILLBRANCHCANDS FALSE /**< should branching candidates be added to storage? */
113 /* conflict analysis */
114 #define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used during conflict analysis? */
116 /**@} */
117 
118 /**@name Event handler properties
119  *
120  * @{
121  */
122 
123 #define EVENTHDLR_NAME "cumulative"
124 #define EVENTHDLR_DESC "bound change event handler for cumulative constraints"
126 /**@} */
127 
128 /*
129  * Data structures
130  */
131 
132 /** constraint data for cumulative constraints */
133 struct SCIP_ConsData
134 {
135  SCIP_VAR** vars; /**< array of variable representing the start time of each job */
136  SCIP_Bool* downlocks; /**< array to store if the variable has a down lock */
137  SCIP_Bool* uplocks; /**< array to store if the variable has an uplock */
138  SCIP_CONS** linkingconss; /**< array of linking constraints for the integer variables */
139  SCIP_ROW** demandrows; /**< array of rows of linear relaxation of this problem */
140  SCIP_ROW** scoverrows; /**< array of rows of small cover cuts of this problem */
141  SCIP_ROW** bcoverrows; /**< array of rows of big cover cuts of this problem */
142  int* demands; /**< array containing corresponding demands */
143  int* durations; /**< array containing corresponding durations */
144  SCIP_Real resstrength1; /**< stores the resource strength 1*/
145  SCIP_Real resstrength2; /**< stores the resource strength 2 */
146  SCIP_Real cumfactor1; /**< stroes the cumulativeness of the constraint */
147  SCIP_Real disjfactor1; /**< stores the disjunctiveness of the constraint */
148  SCIP_Real disjfactor2; /**< stores the disjunctiveness of the constraint */
149  SCIP_Real estimatedstrength;
150  int nvars; /**< number of variables */
151  int varssize; /**< size of the arrays */
152  int ndemandrows; /**< number of rows of cumulative constrint for linear relaxation */
153  int demandrowssize; /**< size of array rows of demand rows */
154  int nscoverrows; /**< number of rows of small cover cuts */
155  int scoverrowssize; /**< size of array of small cover cuts */
156  int nbcoverrows; /**< number of rows of big cover cuts */
157  int bcoverrowssize; /**< size of array of big cover cuts */
158  int capacity; /**< available cumulative capacity */
159 
160  int hmin; /**< left bound of time axis to be considered (including hmin) */
161  int hmax; /**< right bound of time axis to be considered (not including hmax) */
162 
163  unsigned int signature; /**< constraint signature which is need for pairwise comparison */
164 
165  unsigned int validsignature:1; /**< is the signature valid */
166  unsigned int normalized:1; /**< is the constraint normalized */
167  unsigned int covercuts:1; /**< cover cuts are created? */
168  unsigned int propagated:1; /**< is constraint propagted */
169  unsigned int varbounds:1; /**< bool to store if variable bound strengthening was already preformed */
170  unsigned int triedsolving:1; /**< bool to store if we tried already to solve that constraint as independent subproblem */
171 
172 #ifdef SCIP_STATISTIC
173  int maxpeak;
174 #endif
175 };
176 
177 /** constraint handler data */
178 struct SCIP_ConshdlrData
179 {
180  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
181 
182  SCIP_Bool usebinvars; /**< should the binary variables be used? */
183  SCIP_Bool cutsasconss; /**< should the cumulative constraint create cuts as knapsack constraints? */
184  SCIP_Bool ttinfer; /**< should time-table (core-times) propagator be used to infer bounds? */
185  SCIP_Bool efcheck; /**< should edge-finding be used to detect an overload? */
186  SCIP_Bool efinfer; /**< should edge-finding be used to infer bounds? */
187  SCIP_Bool useadjustedjobs; /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
188  SCIP_Bool ttefcheck; /**< should time-table edge-finding be used to detect an overload? */
189  SCIP_Bool ttefinfer; /**< should time-table edge-finding be used to infer bounds? */
190  SCIP_Bool localcuts; /**< should cuts be added only locally? */
191  SCIP_Bool usecovercuts; /**< should covering cuts be added? */
192  SCIP_Bool sepaold; /**< shall old sepa algo be applied? */
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(data1 >= 0 && data1 < (1<<15));
337  assert(data2 >= 0 && data2 < (1<<15));
338 
339  inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
340  inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
341  inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
342 
343  return inferinfo;
344 }
345 
346 /**@} */
347 
348 /*
349  * Local methods
350  */
351 
352 /**@name Miscellaneous Methods
353  *
354  * @{
355  */
356 
357 #ifndef NDEBUG
358 
359 /** compute the core of a job which lies in certain interval [begin, end) */
360 static
362  int begin, /**< begin of the interval */
363  int end, /**< end of the interval */
364  int ect, /**< earliest completion time */
365  int lst /**< latest start time */
366  )
367 {
368  int core;
369 
370  core = MAX(0, MIN(end, ect) - MAX(lst, begin));
371 
372  return core;
373 }
374 #else
375 #define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
376 #endif
377 
378 /** returns the implied earliest start time */ /*lint -e{715}*/
379 static
381  SCIP* scip, /**< SCIP data structure */
382  SCIP_VAR* var, /**< variable for which the implied est should be returned */
383  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
384  int* est /**< pointer to store the implied earliest start time */
385  )
386 { /*lint --e{715}*/
387 #if 0
388  SCIP_VAR** vbdvars;
389  SCIP_VAR* vbdvar;
390  SCIP_Real* vbdcoefs;
391  SCIP_Real* vbdconsts;
392  void* image;
393  int nvbdvars;
394  int v;
395 #endif
396 
397  (*est) = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
398 
399 #if 0
400  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
401 
402  nvbdvars = SCIPvarGetNVlbs(var);
403  vbdvars = SCIPvarGetVlbVars(var);
404  vbdcoefs = SCIPvarGetVlbCoefs(var);
405  vbdconsts = SCIPvarGetVlbConstants(var);
406 
407  for( v = 0; v < nvbdvars; ++v )
408  {
409  vbdvar = vbdvars[v];
410  assert(vbdvar != NULL);
411 
412  image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
413 
414  if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
415  {
416  int duration;
417  int vbdconst;
418 
419  duration = (int)(size_t)image;
420  vbdconst = SCIPconvertRealToInt(scip, vbdconsts[v]);
421 
422  SCIPdebugMsg(scip, "check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
424  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
425 
426  if( duration >= vbdconst )
427  {
428  int impliedest;
429 
430  impliedest = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
431 
432  if( (*est) < impliedest )
433  {
434  (*est) = impliedest;
435 
436  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
437  }
438  }
439  }
440  }
441 #endif
442 
443  return SCIP_OKAY;
444 }
445 
446 /** returns the implied latest completion time */ /*lint -e{715}*/
447 static
449  SCIP* scip, /**< SCIP data structure */
450  SCIP_VAR* var, /**< variable for which the implied est should be returned */
451  int duration, /**< duration of the given job */
452  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
453  int* lct /**< pointer to store the implied latest completion time */
454  )
455 { /*lint --e{715}*/
456 #if 0
457  SCIP_VAR** vbdvars;
458  SCIP_VAR* vbdvar;
459  SCIP_Real* vbdcoefs;
460  SCIP_Real* vbdconsts;
461  int nvbdvars;
462  int v;
463 #endif
464 
465  (*lct) = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
466 
467 #if 0
468  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
469 
470  nvbdvars = SCIPvarGetNVubs(var);
471  vbdvars = SCIPvarGetVubVars(var);
472  vbdcoefs = SCIPvarGetVubCoefs(var);
473  vbdconsts = SCIPvarGetVubConstants(var);
474 
475  for( v = 0; v < nvbdvars; ++v )
476  {
477  vbdvar = vbdvars[v];
478  assert(vbdvar != NULL);
479 
480  if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
481  {
482  int vbdconst;
483 
484  vbdconst = SCIPconvertRealToInt(scip, -vbdconsts[v]);
485 
486  SCIPdebugMsg(scip, "check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
488  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
489 
490  if( duration >= -vbdconst )
491  {
492  int impliedlct;
493 
494  impliedlct = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
495 
496  if( (*lct) > impliedlct )
497  {
498  (*lct) = impliedlct;
499 
500  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
501  }
502  }
503  }
504  }
505 #endif
506 
507  return SCIP_OKAY;
508 }
509 
510 /** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
511 static
513  SCIP* scip, /**< SCIP data structure */
514  SCIP_CONSDATA* consdata, /**< constraint data */
515  SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
516  int** coefs, /**< pointer to store the coefficients */
517  int* nvars, /**< number if collect binary variables */
518  int* startindices, /**< permutation with rspect to the start times */
519  int curtime, /**< current point in time */
520  int nstarted, /**< number of jobs that start before the curtime or at curtime */
521  int nfinished /**< number of jobs that finished before curtime or at curtime */
522  )
523 {
524  int nrowvars;
525  int startindex;
526  int size;
527 
528  size = 10;
529  nrowvars = 0;
530  startindex = nstarted - 1;
531 
532  SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
533  SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
534 
535  /* search for the (nstarted - nfinished) jobs which are active at curtime */
536  while( nstarted - nfinished > nrowvars )
537  {
538  SCIP_VAR* var;
539  int endtime;
540  int duration;
541  int demand;
542  int varidx;
543 
544  /* collect job information */
545  varidx = startindices[startindex];
546  assert(varidx >= 0 && varidx < consdata->nvars);
547 
548  var = consdata->vars[varidx];
549  duration = consdata->durations[varidx];
550  demand = consdata->demands[varidx];
551  assert(var != NULL);
552 
553  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
554 
555  /* check the end time of this job is larger than the curtime; in this case the job is still running */
556  if( endtime > curtime )
557  {
558  SCIP_VAR** binvars;
559  SCIP_Real* vals;
560  int nbinvars;
561  int start;
562  int end;
563  int b;
564 
565  /* check if the linking constraints exists */
566  assert(SCIPexistsConsLinking(scip, var));
567  assert(SCIPgetConsLinking(scip, var) != NULL);
568  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
569 
570  /* collect linking constraint information */
571  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
572  vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
573 
574  start = curtime - duration + 1;
575  end = MIN(curtime, endtime - duration);
576 
577  for( b = 0; b < nbinvars; ++b )
578  {
579  if( vals[b] < start )
580  continue;
581 
582  if( vals[b] > end )
583  break;
584 
585  assert(binvars[b] != NULL);
586 
587  /* ensure array proper array size */
588  if( size == *nvars )
589  {
590  size *= 2;
591  SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
592  SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
593  }
594 
595  (*vars)[*nvars] = binvars[b];
596  (*coefs)[*nvars] = demand;
597  (*nvars)++;
598  }
599  nrowvars++;
600  }
601 
602  startindex--;
603  }
604 
605  return SCIP_OKAY;
606 }
607 
608 /** collect all integer variable which belong to jobs which can run at the point of interest */
609 static
611  SCIP* scip, /**< SCIP data structure */
612  SCIP_CONSDATA* consdata, /**< constraint data */
613  SCIP_VAR*** activevars, /**< jobs that are currently running */
614  int* startindices, /**< permutation with rspect to the start times */
615  int curtime, /**< current point in time */
616  int nstarted, /**< number of jobs that start before the curtime or at curtime */
617  int nfinished, /**< number of jobs that finished before curtime or at curtime */
618  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
619  int* lhs /**< lhs for the new row sum of lbs + minoffset */
620  )
621 {
622  SCIP_VAR* var;
623  int startindex;
624  int endtime;
625  int duration;
626  int starttime;
627 
628  int varidx;
629  int sumofstarts;
630  int mindelta;
631  int counter;
632 
633  assert(curtime >= consdata->hmin);
634  assert(curtime < consdata->hmax);
635 
636  counter = 0;
637  sumofstarts = 0;
638 
639  mindelta = INT_MAX;
640 
641  startindex = nstarted - 1;
642 
643  /* search for the (nstarted - nfinished) jobs which are active at curtime */
644  while( nstarted - nfinished > counter )
645  {
646  assert(startindex >= 0);
647 
648  /* collect job information */
649  varidx = startindices[startindex];
650  assert(varidx >= 0 && varidx < consdata->nvars);
651 
652  var = consdata->vars[varidx];
653  duration = consdata->durations[varidx];
654  assert(duration > 0);
655  assert(var != NULL);
656 
657  if( lower )
658  starttime = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
659  else
660  starttime = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
661 
662  endtime = MIN(starttime + duration, consdata->hmax);
663 
664  /* check the end time of this job is larger than the curtime; in this case the job is still running */
665  if( endtime > curtime )
666  {
667  (*activevars)[counter] = var;
668  sumofstarts += starttime;
669  mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
670  counter++;
671  }
672 
673  startindex--;
674  }
675 
676  assert(mindelta > 0);
677  *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
678 
679  return SCIP_OKAY;
680 }
681 
682 /** initialize the sorted event point arrays */
683 static
685  SCIP* scip, /**< SCIP data structure */
686  int nvars, /**< number of start time variables (activities) */
687  SCIP_VAR** vars, /**< array of start time variables */
688  int* durations, /**< array of durations per start time variable */
689  int* starttimes, /**< array to store sorted start events */
690  int* endtimes, /**< array to store sorted end events */
691  int* startindices, /**< permutation with rspect to the start times */
692  int* endindices, /**< permutation with rspect to the end times */
693  SCIP_Bool local /**< shall local bounds be used */
694  )
695 {
696  SCIP_VAR* var;
697  int j;
698 
699  assert(vars != NULL || nvars == 0);
700 
701  /* assign variables, start and endpoints to arrays */
702  for ( j = 0; j < nvars; ++j )
703  {
704  assert(vars != NULL);
705 
706  var = vars[j];
707  assert(var != NULL);
708 
709  if( local )
710  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
711  else
712  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
713 
714  startindices[j] = j;
715 
716  if( local )
717  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
718  else
719  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
720 
721  endindices[j] = j;
722  }
723 
724  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
725  SCIPsortIntInt(starttimes, startindices, j);
726  SCIPsortIntInt(endtimes, endindices, j);
727 }
728 
729 /** initialize the sorted event point arrays w.r.t. the given primal solutions */
730 static
732  SCIP* scip, /**< SCIP data structure */
733  SCIP_SOL* sol, /**< solution */
734  int nvars, /**< number of start time variables (activities) */
735  SCIP_VAR** vars, /**< array of start time variables */
736  int* durations, /**< array of durations per start time variable */
737  int* starttimes, /**< array to store sorted start events */
738  int* endtimes, /**< array to store sorted end events */
739  int* startindices, /**< permutation with rspect to the start times */
740  int* endindices /**< permutation with rspect to the end times */
741  )
742 {
743  SCIP_VAR* var;
744  int j;
745 
746  assert(vars != NULL || nvars == 0);
747 
748  /* assign variables, start and endpoints to arrays */
749  for ( j = 0; j < nvars; ++j )
750  {
751  assert(vars != NULL);
752 
753  var = vars[j];
754  assert(var != NULL);
755 
756  starttimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
757  startindices[j] = j;
758 
759  endtimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
760  endindices[j] = j;
761  }
762 
763  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
764  SCIPsortIntInt(starttimes, startindices, j);
765  SCIPsortIntInt(endtimes, endindices, j);
766 }
767 
768 /** initialize the sorted event point arrays
769  *
770  * @todo Check the separation process!
771  */
772 static
774  SCIP* scip, /**< SCIP data structure */
775  SCIP_CONSDATA* consdata, /**< constraint data */
776  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
777  int* starttimes, /**< array to store sorted start events */
778  int* endtimes, /**< array to store sorted end events */
779  int* startindices, /**< permutation with rspect to the start times */
780  int* endindices, /**< permutation with rspect to the end times */
781  int* nvars, /**< number of variables that are integral */
782  SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
783  )
784 {
785  SCIP_VAR* var;
786  int tmpnvars;
787  int j;
788 
789  tmpnvars = consdata->nvars;
790  *nvars = 0;
791 
792  /* assign variables, start and endpoints to arrays */
793  for ( j = 0; j < tmpnvars; ++j )
794  {
795  var = consdata->vars[j];
796  assert(var != NULL);
797  assert(consdata->durations[j] > 0);
798  assert(consdata->demands[j] > 0);
799 
800  if( lower )
801  {
802  /* only consider jobs that are at their lower or upper bound */
803  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
804  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
805  continue;
806 
807  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
808  startindices[*nvars] = j;
809 
810  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
811  endindices[*nvars] = j;
812 
813  SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
814  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
815  consdata->durations[j],
816  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
817  consdata->demands[startindices[*nvars]]);
818 
819  (*nvars)++;
820  }
821  else
822  {
823  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
824  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
825  continue;
826 
827  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
828  startindices[*nvars] = j;
829 
830  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
831  endindices[*nvars] = j;
832 
833  SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
834  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
835  consdata->durations[j],
836  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
837  consdata->demands[startindices[*nvars]]);
838 
839  (*nvars)++;
840  }
841  }
842 
843  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
844  SCIPsortIntInt(starttimes, startindices, *nvars);
845  SCIPsortIntInt(endtimes, endindices, *nvars);
846 
847 #ifdef SCIP_DEBUG
848  SCIPdebugMsg(scip, "sorted output %d\n", *nvars);
849 
850  for ( j = 0; j < *nvars; ++j )
851  {
852  SCIPdebugMsg(scip, "%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
853  startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
854  consdata->demands[startindices[j]]);
855  }
856 
857  for ( j = 0; j < *nvars; ++j )
858  {
859  SCIPdebugMsg(scip, "%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
860  consdata->demands[endindices[j]]);
861  }
862 #endif
863 }
864 
865 #ifdef SCIP_STATISTIC
866 /** this method checks for relevant intervals for energetic reasoning */
867 static
868 SCIP_RETCODE computeRelevantEnergyIntervals(
869  SCIP* scip, /**< SCIP data structure */
870  int nvars, /**< number of start time variables (activities) */
871  SCIP_VAR** vars, /**< array of start time variables */
872  int* durations, /**< array of durations */
873  int* demands, /**< array of demands */
874  int capacity, /**< cumulative capacity */
875  int hmin, /**< left bound of time axis to be considered (including hmin) */
876  int hmax, /**< right bound of time axis to be considered (not including hmax) */
877  int** timepoints, /**< array to store relevant points in time */
878  SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
879  int* ntimepoints, /**< pointer to store the number of timepoints */
880  int* maxdemand, /**< pointer to store maximum over all demands */
881  SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
882  )
883 {
884  int* starttimes; /* stores when each job is starting */
885  int* endtimes; /* stores when each job ends */
886  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
887  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
888 
889  SCIP_Real totaldemand;
890  int curtime; /* point in time which we are just checking */
891  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
892 
893  int j;
894 
895  assert( scip != NULL );
896  assert(durations != NULL);
897  assert(demands != NULL);
898  assert(capacity >= 0);
899 
900  /* if no activities are associated with this cumulative then this constraint is redundant */
901  if( nvars == 0 )
902  return SCIP_OKAY;
903 
904  assert(vars != NULL);
905 
906  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
907  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
908  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
909  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
910 
911  /* create event point arrays */
912  createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
913 
914  endindex = 0;
915  totaldemand = 0.0;
916 
917  *ntimepoints = 0;
918  (*timepoints)[0] = starttimes[0];
919  (*cumulativedemands)[0] = 0;
920  *maxdemand = 0;
921 
922  /* check each startpoint of a job whether the capacity is kept or not */
923  for( j = 0; j < nvars; ++j )
924  {
925  int lct;
926  int idx;
927 
928  curtime = starttimes[j];
929 
930  if( curtime >= hmax )
931  break;
932 
933  /* free all capacity usages of jobs the are no longer running */
934  while( endindex < nvars && endtimes[endindex] <= curtime )
935  {
936  int est;
937 
938  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
939  {
940  (*ntimepoints)++;
941  (*timepoints)[*ntimepoints] = endtimes[endindex];
942  (*cumulativedemands)[*ntimepoints] = 0;
943  }
944 
945  idx = endindices[endindex];
946  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
947  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
948  endindex++;
949 
950  (*cumulativedemands)[*ntimepoints] = totaldemand;
951  }
952 
953  idx = startindices[j];
954  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
955  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
956 
957  if( (*timepoints)[*ntimepoints] < curtime )
958  {
959  (*ntimepoints)++;
960  (*timepoints)[*ntimepoints] = curtime;
961  (*cumulativedemands)[*ntimepoints] = 0;
962  }
963 
964  (*cumulativedemands)[*ntimepoints] = totaldemand;
965 
966  /* add the relative capacity requirements for all job which start at the curtime */
967  while( j+1 < nvars && starttimes[j+1] == curtime )
968  {
969  ++j;
970  idx = startindices[j];
971  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
972  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
973 
974  (*cumulativedemands)[*ntimepoints] = totaldemand;
975  }
976  } /*lint --e{850}*/
977 
978  /* free all capacity usages of jobs that are no longer running */
979  while( endindex < nvars/* && endtimes[endindex] < hmax*/)
980  {
981  int est;
982  int idx;
983 
984  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
985  {
986  (*ntimepoints)++;
987  (*timepoints)[*ntimepoints] = endtimes[endindex];
988  (*cumulativedemands)[*ntimepoints] = 0;
989  }
990 
991  idx = endindices[endindex];
992  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
993  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
994  (*cumulativedemands)[*ntimepoints] = totaldemand;
995 
996  ++endindex;
997  }
998 
999  (*ntimepoints)++;
1000  /* compute minimum free capacity */
1001  (*minfreecapacity) = INT_MAX;
1002  for( j = 0; j < *ntimepoints; ++j )
1003  {
1004  if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
1005  *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
1006  }
1007 
1008  /* free buffer arrays */
1009  SCIPfreeBufferArray(scip, &endindices);
1010  SCIPfreeBufferArray(scip, &startindices);
1011  SCIPfreeBufferArray(scip, &endtimes);
1012  SCIPfreeBufferArray(scip, &starttimes);
1013 
1014  return SCIP_OKAY;
1015 }
1016 
1017 /** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1018 static
1019 SCIP_RETCODE evaluateCumulativeness(
1020  SCIP* scip, /**< pointer to scip */
1021  SCIP_CONS* cons /**< cumulative constraint */
1022  )
1023 {
1024  SCIP_CONSDATA* consdata;
1025  int nvars;
1026  int v;
1027  int capacity;
1028 
1029  /* output values: */
1030  SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
1031  SCIP_Real cumfactor1;
1032  SCIP_Real resstrength1; /* overall strength */
1033  SCIP_Real resstrength2; /* timepoint wise maximum */
1034 
1035  /* helpful variables: */
1036  SCIP_Real globalpeak;
1037  SCIP_Real globalmaxdemand;
1038 
1039  /* get constraint data structure */
1040  consdata = SCIPconsGetData(cons);
1041  assert(consdata != NULL);
1042 
1043  nvars = consdata->nvars;
1044  capacity = consdata->capacity;
1045  globalpeak = 0.0;
1046  globalmaxdemand = 0.0;
1047 
1048  disjfactor2 = 0.0;
1049  cumfactor1 = 0.0;
1050  resstrength2 = 0.0;
1051 
1052  /* check each starting time (==each job, but inefficient) */
1053  for( v = 0; v < nvars; ++v )
1054  {
1055  SCIP_Real peak;
1056  SCIP_Real maxdemand;
1057  SCIP_Real deltademand;
1058  int ndemands;
1059  int nlarge;
1060 
1061  int timepoint;
1062  int j;
1063  timepoint = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
1064  peak = consdata->demands[v];
1065  ndemands = 1;
1066  maxdemand = 0;
1067  nlarge = 0;
1068 
1069  if( consdata->demands[v] > capacity / 3 )
1070  nlarge++;
1071 
1072  for( j = 0; j < nvars; ++j )
1073  {
1074  int lb;
1075 
1076  if( j == v )
1077  continue;
1078 
1079  maxdemand = 0.0;
1080  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
1081 
1082  if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
1083  {
1084  peak += consdata->demands[j];
1085  ndemands++;
1086 
1087  if( consdata->demands[j] > consdata->capacity / 3 )
1088  nlarge++;
1089  }
1090  }
1091 
1092  deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
1093  globalpeak = MAX(globalpeak, peak);
1094  globalmaxdemand = MAX(globalmaxdemand, maxdemand);
1095 
1096  if( peak > capacity )
1097  {
1098  disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
1099  cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
1100  resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
1101  }
1102  }
1103 
1104  resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
1105 
1106  consdata->maxpeak = SCIPconvertRealToInt(scip, globalpeak);
1107  consdata->disjfactor2 = disjfactor2;
1108  consdata->cumfactor1 = cumfactor1;
1109  consdata->resstrength2 = resstrength2;
1110  consdata->resstrength1 = resstrength1;
1111 
1112  /* get estimated res strength */
1113  {
1114  int* timepoints;
1115  SCIP_Real* estimateddemands;
1116  int ntimepoints;
1117  int maxdemand;
1118  SCIP_Real minfreecapacity;
1119 
1120  SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
1121  SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
1122 
1123  ntimepoints = 0;
1124  minfreecapacity = INT_MAX;
1125 
1126  SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
1127  consdata->durations, consdata->demands,
1128  capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1129  &ntimepoints, &maxdemand, &minfreecapacity) );
1130 
1131  /* free buffer arrays */
1132  SCIPfreeBufferArray(scip, &estimateddemands);
1133  SCIPfreeBufferArray(scip, &timepoints);
1134 
1135  consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
1136  }
1137 
1138  SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
1139  SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
1140  consdata->estimatedstrength);
1141 
1142  return SCIP_OKAY;
1143 }
1144 #endif
1145 
1146 /** gets the active variables together with the constant */
1147 static
1149  SCIP* scip, /**< SCIP data structure */
1150  SCIP_VAR** var, /**< pointer to store the active variable */
1151  int* scalar, /**< pointer to store the scalar */
1152  int* constant /**< pointer to store the constant */
1153  )
1154 {
1155  if( !SCIPvarIsActive(*var) )
1156  {
1157  SCIP_Real realscalar;
1158  SCIP_Real realconstant;
1159 
1160  realscalar = 1.0;
1161  realconstant = 0.0;
1162 
1164 
1165  /* transform variable to active variable */
1166  SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
1167  assert(!SCIPisZero(scip, realscalar));
1168  assert(SCIPvarIsActive(*var));
1169 
1170  if( realconstant < 0.0 )
1171  (*constant) = -SCIPconvertRealToInt(scip, -realconstant);
1172  else
1173  (*constant) = SCIPconvertRealToInt(scip, realconstant);
1174 
1175  if( realscalar < 0.0 )
1176  (*scalar) = -SCIPconvertRealToInt(scip, -realscalar);
1177  else
1178  (*scalar) = SCIPconvertRealToInt(scip, realscalar);
1179  }
1180  else
1181  {
1182  (*scalar) = 1;
1183  (*constant) = 0;
1184  }
1185 
1186  assert(*scalar != 0);
1187 
1188  return SCIP_OKAY;
1189 }
1190 
1191 /** computes the total energy of all jobs */
1192 static
1194  int* durations, /**< array of job durations */
1195  int* demands, /**< array of job demands */
1196  int njobs /**< number of jobs */
1197  )
1198 {
1199  SCIP_Longint energy;
1200  int j;
1201 
1202  energy = 0;
1203 
1204  for( j = 0; j < njobs; ++j )
1205  energy += (SCIP_Longint) durations[j] * demands[j];
1206 
1207  return energy;
1208 }
1209 
1210 /**@} */
1211 
1212 /**@name Default method to solve a cumulative condition
1213  *
1214  * @{
1215  */
1216 
1217 /** setup and solve subscip to solve single cumulative condition */
1218 static
1220  SCIP* subscip, /**< subscip data structure */
1221  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
1222  int* durations, /**< array of durations */
1223  int* demands, /**< array of demands */
1224  int njobs, /**< number of jobs (activities) */
1225  int capacity, /**< cumulative capacity */
1226  int hmin, /**< left bound of time axis to be considered (including hmin) */
1227  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1228  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes (-1: no limit) */
1229  SCIP_Real timelimit, /**< time limit for solving in seconds */
1230  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
1231  SCIP_Real* ests, /**< array of earliest start times for each job */
1232  SCIP_Real* lsts, /**< array of latest start times for each job */
1233  SCIP_Bool* infeasible, /**< pointer to store if the subproblem was infeasible */
1234  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
1235  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
1236  SCIP_Bool* error /**< pointer to store if an error occurred */
1237  )
1238 {
1239  SCIP_VAR** subvars;
1240  SCIP_CONS* cons;
1241 
1242  char name[SCIP_MAXSTRLEN];
1243  int v;
1244  SCIP_RETCODE retcode;
1245 
1246  assert(subscip != NULL);
1247 
1248  /* copy all plugins */
1250 
1251  /* create the subproblem */
1252  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1253 
1254  SCIP_CALL( SCIPallocBlockMemoryArray(subscip, &subvars, njobs) );
1255 
1256  /* create for each job a start time variable */
1257  for( v = 0; v < njobs; ++v )
1258  {
1259  SCIP_Real objval;
1260 
1261  /* construct variable name */
1262  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
1263 
1264  if( objvals == NULL )
1265  objval = 0.0;
1266  else
1267  objval = objvals[v];
1268 
1269  SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
1270  SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
1271  }
1272 
1273  /* create cumulative constraint */
1274  SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
1275  njobs, subvars, durations, demands, capacity) );
1276 
1277  /* set effective horizon */
1278  SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
1279  SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
1280 
1281  /* add cumulative constraint */
1282  SCIP_CALL( SCIPaddCons(subscip, cons) );
1283  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1284 
1285  /* set CP solver settings
1286  *
1287  * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
1288  * time limit.
1289  */
1291 
1292  /* do not abort subproblem on CTRL-C */
1293  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1294 
1295  /* disable output to console */
1296  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1297 
1298  /* set limits for the subproblem */
1299  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1300  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1301  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1302 
1303  /* forbid recursive call of heuristics and separators solving subMIPs */
1304  SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
1305 
1306  /* solve single cumulative constraint by branch and bound */
1307  retcode = SCIPsolve(subscip);
1308 
1309  if( retcode != SCIP_OKAY )
1310  (*error) = TRUE;
1311  else
1312  {
1313  SCIPdebugMsg(subscip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1314 
1315  /* evaluated solution status */
1316  switch( SCIPgetStatus(subscip) )
1317  {
1318  case SCIP_STATUS_INFORUNBD:
1320  (*infeasible) = TRUE;
1321  (*solved) = TRUE;
1322  break;
1323  case SCIP_STATUS_UNBOUNDED:
1324  (*unbounded) = TRUE;
1325  (*solved) = TRUE;
1326  break;
1327  case SCIP_STATUS_OPTIMAL:
1328  {
1329  SCIP_SOL* sol;
1330  SCIP_Real solval;
1331 
1332  sol = SCIPgetBestSol(subscip);
1333  assert(sol != NULL);
1334 
1335  for( v = 0; v < njobs; ++v )
1336  {
1337  solval = SCIPgetSolVal(subscip, sol, subvars[v]);
1338 
1339  ests[v] = solval;
1340  lsts[v] = solval;
1341  }
1342  (*solved) = TRUE;
1343  break;
1344  }
1345  case SCIP_STATUS_NODELIMIT:
1347  case SCIP_STATUS_TIMELIMIT:
1348  case SCIP_STATUS_MEMLIMIT:
1350  case SCIP_STATUS_TERMINATE:
1351  /* transfer the global bound changes */
1352  for( v = 0; v < njobs; ++v )
1353  {
1354  ests[v] = SCIPvarGetLbGlobal(subvars[v]);
1355  lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
1356  }
1357  (*solved) = FALSE;
1358  break;
1359 
1360  case SCIP_STATUS_UNKNOWN:
1362  case SCIP_STATUS_GAPLIMIT:
1363  case SCIP_STATUS_SOLLIMIT:
1366  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1367  return SCIP_INVALIDDATA;
1368  }
1369  }
1370 
1371  /* release all variables */
1372  for( v = 0; v < njobs; ++v )
1373  {
1374  SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1375  }
1376 
1377  SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
1378 
1379  return SCIP_OKAY;
1380 }
1381 
1382 /** solve single cumulative condition using SCIP and a single cumulative constraint */
1383 static
1384 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1386  SCIP* subscip;
1387 
1388  SCIP_RETCODE retcode;
1389 
1390  assert(njobs > 0);
1391 
1392  (*solved) = FALSE;
1393  (*infeasible) = FALSE;
1394  (*unbounded) = FALSE;
1395  (*error) = FALSE;
1396 
1397  SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1398 
1399  /* initialize the sub-problem */
1400  SCIP_CALL( SCIPcreate(&subscip) );
1401 
1402  /* create and solve the subproblem. catch possible errors */
1403  retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
1404  njobs, capacity, hmin, hmax,
1405  maxnodes, timelimit, memorylimit,
1406  ests, lsts,
1407  infeasible, unbounded, solved, error);
1408 
1409  /* free the subscip in any case */
1410  SCIP_CALL( SCIPfree(&subscip) );
1411 
1412  SCIP_CALL( retcode );
1413 
1414  return SCIP_OKAY;
1415 }
1416 
1417 #if 0
1418 /** solve single cumulative condition using SCIP and the time indexed formulation */
1419 static
1420 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1421 {
1422  SCIP* subscip;
1423  SCIP_VAR*** binvars;
1424  SCIP_RETCODE retcode;
1425  char name[SCIP_MAXSTRLEN];
1426  int minest;
1427  int maxlct;
1428  int t;
1429  int v;
1430 
1431  assert(njobs > 0);
1432 
1433  (*solved) = FALSE;
1434  (*infeasible) = FALSE;
1435  (*unbounded) = FALSE;
1436  (*error) = FALSE;
1437 
1438  SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
1439 
1440  /* initialize the sub-problem */
1441  SCIP_CALL( SCIPcreate(&subscip) );
1442 
1443  /* copy all plugins */
1445 
1446  /* create the subproblem */
1447  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1448 
1449  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
1450 
1451  minest = INT_MAX;
1452  maxlct = INT_MIN;
1453 
1454  /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1455  * partitioning constrain which forces that job starts
1456  */
1457  for( v = 0; v < njobs; ++v )
1458  {
1459  SCIP_CONS* cons;
1460  SCIP_Real objval;
1461  int timeinterval;
1462  int est;
1463  int lst;
1464 
1465  if( objvals == NULL )
1466  objval = 0.0;
1467  else
1468  objval = objvals[v];
1469 
1470  est = ests[v];
1471  lst = lsts[v];
1472 
1473  /* compute number of possible start points */
1474  timeinterval = lst - est + 1;
1475  assert(timeinterval > 0);
1476 
1477  /* compute the smallest earliest start time and largest latest completion time */
1478  minest = MIN(minest, est);
1479  maxlct = MAX(maxlct, lst + durations[v]);
1480 
1481  /* construct constraint name */
1482  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1483 
1484  SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1485 
1486  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
1487 
1488  for( t = 0; t < timeinterval; ++t )
1489  {
1490  SCIP_VAR* binvar;
1491 
1492  /* construct varibale name */
1493  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1494 
1495  SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1496  SCIP_CALL( SCIPaddVar(subscip, binvar) );
1497 
1498  /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1499  SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1500 
1501  binvars[v][t] = binvar;
1502  }
1503 
1504  /* add and release the set partitioning constraint */
1505  SCIP_CALL( SCIPaddCons(subscip, cons) );
1506  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1507  }
1508 
1509  /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1510  hmin = MAX(hmin, minest);
1511  hmax = MIN(hmax, maxlct);
1512  assert(hmin > INT_MIN);
1513  assert(hmax < INT_MAX);
1514  assert(hmin < hmax);
1515 
1516  /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1517  for( t = hmin; t < hmax; ++t )
1518  {
1519  SCIP_CONS* cons;
1520 
1521  /* construct constraint name */
1522  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1523 
1524  /* create an empty knapsack constraint */
1525  SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1526 
1527  /* add all jobs which potentially can be processed at that time point */
1528  for( v = 0; v < njobs; ++v )
1529  {
1530  int duration;
1531  int demand;
1532  int start;
1533  int end;
1534  int est;
1535  int lst;
1536  int k;
1537 
1538  est = ests[v];
1539  lst = lsts[v] ;
1540 
1541  duration = durations[v];
1542  assert(duration > 0);
1543 
1544  /* check if the varibale is processed potentially at time point t */
1545  if( t < est || t >= lst + duration )
1546  continue;
1547 
1548  demand = demands[v];
1549  assert(demand >= 0);
1550 
1551  start = MAX(t - duration + 1, est);
1552  end = MIN(t, lst);
1553 
1554  assert(start <= end);
1555 
1556  for( k = start; k <= end; ++k )
1557  {
1558  assert(binvars[v][k] != NULL);
1559  SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1560  }
1561  }
1562 
1563  /* add and release the knapsack constraint */
1564  SCIP_CALL( SCIPaddCons(subscip, cons) );
1565  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1566  }
1567 
1568  /* do not abort subproblem on CTRL-C */
1569  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1570 
1571  /* disable output to console */
1572  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1573 
1574  /* set limits for the subproblem */
1575  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1576  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1577  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1578 
1579  /* solve single cumulative constraint by branch and bound */
1580  retcode = SCIPsolve(subscip);
1581 
1582  if( retcode != SCIP_OKAY )
1583  (*error) = TRUE;
1584  else
1585  {
1586  SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1587 
1588  /* evaluated solution status */
1589  switch( SCIPgetStatus(subscip) )
1590  {
1591  case SCIP_STATUS_INFORUNBD:
1593  (*infeasible) = TRUE;
1594  (*solved) = TRUE;
1595  break;
1596  case SCIP_STATUS_UNBOUNDED:
1597  (*unbounded) = TRUE;
1598  (*solved) = TRUE;
1599  break;
1600  case SCIP_STATUS_OPTIMAL:
1601  {
1602  SCIP_SOL* sol;
1603 
1604  sol = SCIPgetBestSol(subscip);
1605  assert(sol != NULL);
1606 
1607  for( v = 0; v < njobs; ++v )
1608  {
1609  int timeinterval;
1610  int est;
1611  int lst;
1612 
1613  est = ests[v];
1614  lst = lsts[v];
1615 
1616  /* compute number of possible start points */
1617  timeinterval = lst - est + 1;
1618 
1619  /* check which binary varibale is set to one */
1620  for( t = 0; t < timeinterval; ++t )
1621  {
1622  if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1623  {
1624  ests[v] = est + t;
1625  lsts[v] = est + t;
1626  break;
1627  }
1628  }
1629  }
1630 
1631  (*solved) = TRUE;
1632  break;
1633  }
1634  case SCIP_STATUS_NODELIMIT:
1636  case SCIP_STATUS_TIMELIMIT:
1637  case SCIP_STATUS_MEMLIMIT:
1639  /* transfer the global bound changes */
1640  for( v = 0; v < njobs; ++v )
1641  {
1642  int timeinterval;
1643  int est;
1644  int lst;
1645 
1646  est = ests[v];
1647  lst = lsts[v];
1648 
1649  /* compute number of possible start points */
1650  timeinterval = lst - est + 1;
1651 
1652  /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1653  for( t = 0; t < timeinterval; ++t )
1654  {
1655  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1656  {
1657  ests[v] = est + t;
1658  break;
1659  }
1660  }
1661 
1662  /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1663  for( t = timeinterval - 1; t >= 0; --t )
1664  {
1665  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1666  {
1667  lsts[v] = est + t;
1668  break;
1669  }
1670  }
1671  }
1672  (*solved) = FALSE;
1673  break;
1674 
1675  case SCIP_STATUS_UNKNOWN:
1677  case SCIP_STATUS_GAPLIMIT:
1678  case SCIP_STATUS_SOLLIMIT:
1680  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1681  return SCIP_INVALIDDATA;
1682  }
1683  }
1684 
1685  /* release all variables */
1686  for( v = 0; v < njobs; ++v )
1687  {
1688  int timeinterval;
1689  int est;
1690  int lst;
1691 
1692  est = ests[v];
1693  lst = lsts[v];
1694 
1695  /* compute number of possible start points */
1696  timeinterval = lst - est + 1;
1697 
1698  for( t = 0; t < timeinterval; ++t )
1699  {
1700  SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1701  }
1702  SCIPfreeBufferArray(subscip, &binvars[v]);
1703  }
1704 
1705  SCIPfreeBufferArray(subscip, &binvars);
1706 
1707  SCIP_CALL( SCIPfree(&subscip) );
1708 
1709  return SCIP_OKAY;
1710 }
1711 #endif
1712 
1713 /**@} */
1714 
1715 /**@name Constraint handler data
1716  *
1717  * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1718  * handler.
1719  *
1720  * @{
1721  */
1722 
1723 /** creates constaint handler data for cumulative constraint handler */
1724 static
1726  SCIP* scip, /**< SCIP data structure */
1727  SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1728  SCIP_EVENTHDLR* eventhdlr /**< event handler */
1729  )
1730 {
1731  /* create precedence constraint handler data */
1732  assert(scip != NULL);
1733  assert(conshdlrdata != NULL);
1734  assert(eventhdlr != NULL);
1735 
1736  SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
1737 
1738  /* set event handler for checking if bounds of start time variables are tighten */
1739  (*conshdlrdata)->eventhdlr = eventhdlr;
1740 
1741  /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1742  (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1743 
1744 #ifdef SCIP_STATISTIC
1745  (*conshdlrdata)->nlbtimetable = 0;
1746  (*conshdlrdata)->nubtimetable = 0;
1747  (*conshdlrdata)->ncutofftimetable = 0;
1748  (*conshdlrdata)->nlbedgefinder = 0;
1749  (*conshdlrdata)->nubedgefinder = 0;
1750  (*conshdlrdata)->ncutoffedgefinder = 0;
1751  (*conshdlrdata)->ncutoffoverload = 0;
1752  (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1753 
1754  (*conshdlrdata)->nirrelevantjobs = 0;
1755  (*conshdlrdata)->nalwaysruns = 0;
1756  (*conshdlrdata)->nremovedlocks = 0;
1757  (*conshdlrdata)->ndualfixs = 0;
1758  (*conshdlrdata)->ndecomps = 0;
1759  (*conshdlrdata)->ndualbranchs = 0;
1760  (*conshdlrdata)->nallconsdualfixs = 0;
1761  (*conshdlrdata)->naddedvarbounds = 0;
1762  (*conshdlrdata)->naddeddisjunctives = 0;
1763 #endif
1764 
1765  return SCIP_OKAY;
1766 }
1767 
1768 /** frees constraint handler data for logic or constraint handler */
1769 static
1770 void conshdlrdataFree(
1771  SCIP* scip, /**< SCIP data structure */
1772  SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1773  )
1774 {
1775  assert(conshdlrdata != NULL);
1776  assert(*conshdlrdata != NULL);
1777 
1778  SCIPfreeBlockMemory(scip, conshdlrdata);
1779 }
1780 
1781 /**@} */
1782 
1783 
1784 /**@name Constraint data methods
1785  *
1786  * @{
1787  */
1788 
1789 /** catches bound change events for all variables in transformed cumulative constraint */
1790 static
1792  SCIP* scip, /**< SCIP data structure */
1793  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1794  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1795  )
1796 {
1797  int v;
1798 
1799  assert(scip != NULL);
1800  assert(consdata != NULL);
1801  assert(eventhdlr != NULL);
1802 
1803  /* catch event for every single variable */
1804  for( v = 0; v < consdata->nvars; ++v )
1805  {
1806  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1807  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1808  }
1809 
1810  return SCIP_OKAY;
1811 }
1812 
1813 /** drops events for variable at given position */
1814 static
1816  SCIP* scip, /**< SCIP data structure */
1817  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1818  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1819  int pos /**< array position of variable to catch bound change events for */
1820  )
1821 {
1822  assert(scip != NULL);
1823  assert(consdata != NULL);
1824  assert(eventhdlr != NULL);
1825  assert(0 <= pos && pos < consdata->nvars);
1826  assert(consdata->vars[pos] != NULL);
1827 
1828  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1829  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1830 
1831  return SCIP_OKAY;
1832 }
1833 
1834 /** drops bound change events for all variables in transformed linear constraint */
1835 static
1837  SCIP* scip, /**< SCIP data structure */
1838  SCIP_CONSDATA* consdata, /**< linear constraint data */
1839  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1840  )
1841 {
1842  int v;
1843 
1844  assert(scip != NULL);
1845  assert(consdata != NULL);
1846 
1847  /* drop event of every single variable */
1848  for( v = 0; v < consdata->nvars; ++v )
1849  {
1850  SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1851  }
1852 
1853  return SCIP_OKAY;
1854 }
1855 
1856 /** initialize variable lock data structure */
1857 static
1858 void initializeLocks(
1859  SCIP_CONSDATA* consdata, /**< constraint data */
1860  SCIP_Bool locked /**< should the variable be locked? */
1861  )
1862 {
1863  int nvars;
1864  int v;
1865 
1866  nvars = consdata->nvars;
1867 
1868  /* initialize locking arrays */
1869  for( v = 0; v < nvars; ++v )
1870  {
1871  consdata->downlocks[v] = locked;
1872  consdata->uplocks[v] = locked;
1873  }
1874 }
1875 
1876 /** creates constraint data of cumulative constraint */
1877 static
1879  SCIP* scip, /**< SCIP data structure */
1880  SCIP_CONSDATA** consdata, /**< pointer to consdata */
1881  SCIP_VAR** vars, /**< array of integer variables */
1882  SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1883  int* durations, /**< array containing corresponding durations */
1884  int* demands, /**< array containing corresponding demands */
1885  int nvars, /**< number of variables */
1886  int capacity, /**< available cumulative capacity */
1887  int hmin, /**< left bound of time axis to be considered (including hmin) */
1888  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1889  SCIP_Bool check /**< is the corresponding constraint a check constraint */
1890  )
1891 {
1892  int v;
1893 
1894  assert(scip != NULL);
1895  assert(consdata != NULL);
1896  assert(vars != NULL || nvars > 0);
1897  assert(demands != NULL);
1898  assert(durations != NULL);
1899  assert(capacity >= 0);
1900  assert(hmin >= 0);
1901  assert(hmin < hmax);
1902 
1903  /* create constraint data */
1904  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1905 
1906  (*consdata)->hmin = hmin;
1907  (*consdata)->hmax = hmax;
1908 
1909  (*consdata)->capacity = capacity;
1910  (*consdata)->demandrows = NULL;
1911  (*consdata)->demandrowssize = 0;
1912  (*consdata)->ndemandrows = 0;
1913  (*consdata)->scoverrows = NULL;
1914  (*consdata)->nscoverrows = 0;
1915  (*consdata)->scoverrowssize = 0;
1916  (*consdata)->bcoverrows = NULL;
1917  (*consdata)->nbcoverrows = 0;
1918  (*consdata)->bcoverrowssize = 0;
1919  (*consdata)->nvars = nvars;
1920  (*consdata)->varssize = nvars;
1921  (*consdata)->signature = 0;
1922  (*consdata)->validsignature = FALSE;
1923  (*consdata)->normalized = FALSE;
1924  (*consdata)->covercuts = FALSE;
1925  (*consdata)->propagated = FALSE;
1926  (*consdata)->varbounds = FALSE;
1927  (*consdata)->triedsolving = FALSE;
1928 
1929  if( nvars > 0 )
1930  {
1931  assert(vars != NULL); /* for flexelint */
1932 
1933  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1934  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1935  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1936  (*consdata)->linkingconss = NULL;
1937 
1938  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1939  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1940 
1941  /* initialize variable lock data structure; the locks are only used if the contraint is a check constraint */
1942  initializeLocks(*consdata, check);
1943 
1944  if( linkingconss != NULL )
1945  {
1946  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
1947  }
1948 
1949  /* transform variables, if they are not yet transformed */
1950  if( SCIPisTransformed(scip) )
1951  {
1952  SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
1953 
1954  /* get transformed variables and do NOT captures these */
1955  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1956 
1957  /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
1958  * been multi-aggregated
1959  */
1960  for( v = 0; v < nvars; ++v )
1961  {
1962  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
1963  }
1964 
1965  if( linkingconss != NULL )
1966  {
1967  /* get transformed constraints and captures these */
1968  SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
1969 
1970  for( v = 0; v < nvars; ++v )
1971  assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
1972  }
1973  }
1974  }
1975  else
1976  {
1977  (*consdata)->vars = NULL;
1978  (*consdata)->downlocks = NULL;
1979  (*consdata)->uplocks = NULL;
1980  (*consdata)->demands = NULL;
1981  (*consdata)->durations = NULL;
1982  (*consdata)->linkingconss = NULL;
1983  }
1984 
1985  /* initialize values for running propagation algorithms efficiently */
1986  (*consdata)->resstrength1 = -1.0;
1987  (*consdata)->resstrength2 = -1.0;
1988  (*consdata)->cumfactor1 = -1.0;
1989  (*consdata)->disjfactor1 = -1.0;
1990  (*consdata)->disjfactor2 = -1.0;
1991  (*consdata)->estimatedstrength = -1.0;
1992 
1993  SCIPstatistic( (*consdata)->maxpeak = -1 );
1994 
1995  return SCIP_OKAY;
1996 }
1997 
1998 /** releases LP rows of constraint data and frees rows array */
1999 static
2001  SCIP* scip, /**< SCIP data structure */
2002  SCIP_CONSDATA** consdata /**< constraint data */
2003  )
2004 {
2005  int r;
2006 
2007  assert(consdata != NULL);
2008  assert(*consdata != NULL);
2009 
2010  for( r = 0; r < (*consdata)->ndemandrows; ++r )
2011  {
2012  assert((*consdata)->demandrows[r] != NULL);
2013  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
2014  }
2015 
2016  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
2017 
2018  (*consdata)->ndemandrows = 0;
2019  (*consdata)->demandrowssize = 0;
2020 
2021  /* free rows of cover cuts */
2022  for( r = 0; r < (*consdata)->nscoverrows; ++r )
2023  {
2024  assert((*consdata)->scoverrows[r] != NULL);
2025  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
2026  }
2027 
2028  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
2029 
2030  (*consdata)->nscoverrows = 0;
2031  (*consdata)->scoverrowssize = 0;
2032 
2033  for( r = 0; r < (*consdata)->nbcoverrows; ++r )
2034  {
2035  assert((*consdata)->bcoverrows[r] != NULL);
2036  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2037  }
2038 
2039  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2040 
2041  (*consdata)->nbcoverrows = 0;
2042  (*consdata)->bcoverrowssize = 0;
2043 
2044  (*consdata)->covercuts = FALSE;
2045 
2046  return SCIP_OKAY;
2047 }
2048 
2049 /** frees a cumulative constraint data */
2050 static
2052  SCIP* scip, /**< SCIP data structure */
2053  SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2054  )
2055 {
2056  int varssize;
2057  int nvars;
2058 
2059  assert(consdata != NULL);
2060  assert(*consdata != NULL);
2061 
2062  nvars = (*consdata)->nvars;
2063  varssize = (*consdata)->varssize;
2064 
2065  if( varssize > 0 )
2066  {
2067  int v;
2068 
2069  /* release and free the rows */
2070  SCIP_CALL( consdataFreeRows(scip, consdata) );
2071 
2072  /* release the linking constraints if they were generated */
2073  if( (*consdata)->linkingconss != NULL )
2074  {
2075  for( v = nvars-1; v >= 0; --v )
2076  {
2077  assert((*consdata)->linkingconss[v] != NULL );
2078  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2079  }
2080 
2081  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2082  }
2083 
2084  /* free arrays */
2085  SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2086  SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2087  SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2088  SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2089  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2090  }
2091 
2092  /* free memory */
2093  SCIPfreeBlockMemory(scip, consdata);
2094 
2095  return SCIP_OKAY;
2096 }
2097 
2098 /** prints cumulative constraint to file stream */
2099 static
2100 void consdataPrint(
2101  SCIP* scip, /**< SCIP data structure */
2102  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2103  FILE* file /**< output file (or NULL for standard output) */
2104  )
2105 {
2106  int v;
2107 
2108  assert(consdata != NULL);
2109 
2110  /* print coefficients */
2111  SCIPinfoMessage( scip, file, "cumulative(");
2112 
2113  for( v = 0; v < consdata->nvars; ++v )
2114  {
2115  assert(consdata->vars[v] != NULL);
2116  if( v > 0 )
2117  SCIPinfoMessage(scip, file, ", ");
2118  SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2119  SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2120  consdata->durations[v], consdata->demands[v]);
2121  }
2122  SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2123 }
2124 
2125 /** deletes coefficient at given position from constraint data */
2126 static
2128  SCIP* scip, /**< SCIP data structure */
2129  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2130  SCIP_CONS* cons, /**< knapsack constraint */
2131  int pos /**< position of coefficient to delete */
2132  )
2133 {
2134  SCIP_CONSHDLR* conshdlr;
2135  SCIP_CONSHDLRDATA* conshdlrdata;
2136 
2137  assert(scip != NULL);
2138  assert(consdata != NULL);
2139  assert(cons != NULL);
2140  assert(SCIPconsIsTransformed(cons));
2141  assert(!SCIPinProbing(scip));
2142 
2143  SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2144  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2145 
2146  /* remove the rounding locks for the deleted variable */
2147  SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2148 
2149  consdata->downlocks[pos] = FALSE;
2150  consdata->uplocks[pos] = FALSE;
2151 
2152  if( consdata->linkingconss != NULL )
2153  {
2154  SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2155  }
2156 
2157  /* get event handler */
2158  conshdlr = SCIPconsGetHdlr(cons);
2159  assert(conshdlr != NULL);
2160  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2161  assert(conshdlrdata != NULL);
2162  assert(conshdlrdata->eventhdlr != NULL);
2163 
2164  /* drop events */
2165  SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2166 
2167  SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2168  SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2169 
2170  /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2171  * position
2172  */
2173  if( pos != consdata->nvars - 1 )
2174  {
2175  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2176  consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2177  consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2178  consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2179  consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2180 
2181  if( consdata->linkingconss != NULL )
2182  {
2183  consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2184  }
2185  }
2186 
2187  consdata->nvars--;
2188  consdata->validsignature = FALSE;
2189  consdata->normalized = FALSE;
2190 
2191  return SCIP_OKAY;
2192 }
2193 
2194 /** collect linking constraints for each integer variable */
2195 static
2197  SCIP* scip, /**< SCIP data structure */
2198  SCIP_CONSDATA* consdata /**< pointer to consdata */
2199  )
2200 {
2201  int nvars;
2202  int v;
2203 
2204  assert(scip != NULL);
2205  assert(consdata != NULL);
2206 
2207  nvars = consdata->nvars;
2208  assert(nvars > 0);
2209  assert(consdata->linkingconss == NULL);
2210 
2211  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2212 
2213  for( v = 0; v < nvars; ++v )
2214  {
2215  SCIP_CONS* cons;
2216  SCIP_VAR* var;
2217 
2218  var = consdata->vars[v];
2219  assert(var != NULL);
2220 
2221  SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2222 
2223  /* create linking constraint if it does not exist yet */
2224  if( !SCIPexistsConsLinking(scip, var) )
2225  {
2226  char name[SCIP_MAXSTRLEN];
2227 
2228  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2229 
2230  /* creates and captures an linking constraint */
2231  SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2232  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2233  SCIP_CALL( SCIPaddCons(scip, cons) );
2234  consdata->linkingconss[v] = cons;
2235  }
2236  else
2237  {
2238  consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2239  SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2240  }
2241 
2242  assert(SCIPexistsConsLinking(scip, var));
2243  assert(consdata->linkingconss[v] != NULL);
2244  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2245  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2246  }
2247 
2248  return SCIP_OKAY;
2249 }
2250 
2251 /**@} */
2252 
2253 
2254 /**@name Check methods
2255  *
2256  * @{
2257  */
2258 
2259 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2260  * given solution is satisfied
2261  */
2262 static
2264  SCIP* scip, /**< SCIP data structure */
2265  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2266  int nvars, /**< number of variables (jobs) */
2267  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2268  int* durations, /**< array containing corresponding durations */
2269  int* demands, /**< array containing corresponding demands */
2270  int capacity, /**< available cumulative capacity */
2271  int hmin, /**< left bound of time axis to be considered (including hmin) */
2272  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2273  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2274  SCIP_CONS* cons, /**< constraint which is checked */
2275  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2276  )
2277 {
2278  int* startsolvalues; /* stores when each job is starting */
2279  int* endsolvalues; /* stores when each job ends */
2280  int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2281  int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2282 
2283  int freecapacity;
2284  int curtime; /* point in time which we are just checking */
2285  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2286  int j;
2287 
2288  SCIP_Real absviol;
2289  SCIP_Real relviol;
2290 
2291  assert(scip != NULL);
2292  assert(violated != NULL);
2293 
2294  (*violated) = FALSE;
2295 
2296  if( nvars == 0 )
2297  return SCIP_OKAY;
2298 
2299  assert(vars != NULL);
2300  assert(demands != NULL);
2301  assert(durations != NULL);
2302 
2303  /* compute time points where we have to check whether capacity constraint is infeasible or not */
2304  SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2305  SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2306  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2307  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2308 
2309  /* assign variables, start and endpoints to arrays */
2310  for ( j = 0; j < nvars; ++j )
2311  {
2312  int solvalue;
2313 
2314  /* the constraint of the cumulative constraint handler should be called after the integrality check */
2315  assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2316 
2317  solvalue = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2318 
2319  /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2320  * jobs which start before hmin to hmin
2321  */
2322  startsolvalues[j] = MAX(solvalue, hmin);
2323  startindices[j] = j;
2324 
2325  endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2326  endindices[j] = j;
2327  }
2328 
2329  /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2330  * corresponding indices in the same way)
2331  */
2332  SCIPsortIntInt(startsolvalues, startindices, nvars);
2333  SCIPsortIntInt(endsolvalues, endindices, nvars);
2334 
2335  endindex = 0;
2336  freecapacity = capacity;
2337  absviol = 0.0;
2338  relviol = 0.0;
2339 
2340  /* check each start point of a job whether the capacity is kept or not */
2341  for( j = 0; j < nvars; ++j )
2342  {
2343  /* only check intervals [hmin,hmax) */
2344  curtime = startsolvalues[j];
2345 
2346  if( curtime >= hmax )
2347  break;
2348 
2349  /* subtract all capacity needed up to this point */
2350  freecapacity -= demands[startindices[j]];
2351  while( j+1 < nvars && startsolvalues[j+1] == curtime )
2352  {
2353  j++;
2354  freecapacity -= demands[startindices[j]];
2355  }
2356 
2357  /* free all capacity usages of jobs that are no longer running */
2358  while( endindex < nvars && curtime >= endsolvalues[endindex] )
2359  {
2360  freecapacity += demands[endindices[endindex]];
2361  ++endindex;
2362  }
2363  assert(freecapacity <= capacity);
2364 
2365  /* update absolute and relative violation */
2366  if( absviol < (SCIP_Real) (-freecapacity) )
2367  {
2368  absviol = -freecapacity;
2369  relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
2370  }
2371 
2372  /* check freecapacity to be smaller than zero */
2373  if( freecapacity < 0 && curtime >= hmin )
2374  {
2375  SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2376  (*violated) = TRUE;
2377 
2378  if( printreason )
2379  {
2380  int i;
2381 
2382  /* first state the violated constraints */
2383  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2384 
2385  /* second state the reason */
2386  SCIPinfoMessage(scip, NULL,
2387  ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2388  curtime, capacity, capacity - freecapacity);
2389 
2390  for( i = 0; i <= j; ++i )
2391  {
2392  if( startsolvalues[i] + durations[startindices[i]] > curtime )
2393  {
2394  SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2395  SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2396  demands[startindices[i]]);
2397  }
2398  }
2399  }
2400  break;
2401  }
2402  } /*lint --e{850}*/
2403 
2404  /* update constraint violation in solution */
2405  if( sol != NULL )
2406  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
2407 
2408  /* free all buffer arrays */
2409  SCIPfreeBufferArray(scip, &endindices);
2410  SCIPfreeBufferArray(scip, &startindices);
2411  SCIPfreeBufferArray(scip, &endsolvalues);
2412  SCIPfreeBufferArray(scip, &startsolvalues);
2413 
2414  return SCIP_OKAY;
2415 }
2416 
2417 /** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2418  * least zero or not. If not (*violated) is set to TRUE
2419  */
2420 static
2422  SCIP* scip, /**< SCIP data structure */
2423  SCIP_CONS* cons, /**< constraint to be checked */
2424  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2425  SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2426  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2427  )
2428 {
2429  SCIP_CONSDATA* consdata;
2430 
2431  assert(scip != NULL);
2432  assert(cons != NULL);
2433  assert(violated != NULL);
2434 
2435  SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2436 
2437  consdata = SCIPconsGetData(cons);
2438  assert(consdata != NULL);
2439 
2440  /* check the cumulative condition */
2441  SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2442  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2443  violated, cons, printreason) );
2444 
2445  return SCIP_OKAY;
2446 }
2447 
2448 /**@} */
2449 
2450 /**@name Conflict analysis
2451  *
2452  * @{
2453  */
2454 
2455 /** resolves the propagation of the core time algorithm */
2456 static
2458  SCIP* scip, /**< SCIP data structure */
2459  int nvars, /**< number of start time variables (activities) */
2460  SCIP_VAR** vars, /**< array of start time variables */
2461  int* durations, /**< array of durations */
2462  int* demands, /**< array of demands */
2463  int capacity, /**< cumulative capacity */
2464  int hmin, /**< left bound of time axis to be considered (including hmin) */
2465  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2466  SCIP_VAR* infervar, /**< inference variable */
2467  int inferdemand, /**< demand of the inference variable */
2468  int inferpeak, /**< time point which causes the propagation */
2469  int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2470  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2471  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2472  int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2473  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2474  )
2475 {
2476  SCIP_VAR* var;
2477  SCIP_Bool* reported;
2478  int duration;
2479  int maxlst;
2480  int minect;
2481  int ect;
2482  int lst;
2483  int j;
2484 
2485  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
2486 
2487  SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2488  SCIPvarGetName(infervar), inferdemand, inferpeak);
2489  assert(nvars > 0);
2490 
2491  /* adjusted capacity */
2492  capacity -= inferdemand;
2493  maxlst = INT_MIN;
2494  minect = INT_MAX;
2495 
2496  SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2497  BMSclearMemoryArray(reported, nvars);
2498 
2499  /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2500  * inference peak and those where the current conflict bounds provide a core at the inference peak
2501  */
2502  for( j = 0; j < nvars && capacity >= 0; ++j )
2503  {
2504  var = vars[j];
2505  assert(var != NULL);
2506 
2507  /* skip inference variable */
2508  if( var == infervar )
2509  continue;
2510 
2511  duration = durations[j];
2512  assert(duration > 0);
2513 
2514  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2515  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2516  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2517  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2518  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2519 
2520  SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2522  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2523 
2524  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2525  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2526 
2527  /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2528  * that job without adding it the explanation
2529  */
2530  if( inferpeak < ect && lst <= inferpeak )
2531  {
2532  capacity -= demands[j];
2533  reported[j] = TRUE;
2534 
2535  maxlst = MAX(maxlst, lst);
2536  minect = MIN(minect, ect);
2537  assert(maxlst < minect);
2538 
2539  if( explanation != NULL )
2540  explanation[j] = TRUE;
2541 
2542  continue;
2543  }
2544 
2545  /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2546  * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2547  * not part of the conflict yet we get the global bounds back.
2548  */
2549  ect = SCIPconvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2550  lst = SCIPconvertRealToInt(scip, SCIPgetConflictVarUb(scip, var));
2551 
2552  /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2553  * of that job without and collect the job as part of the explanation
2554  *
2555  * @note we do not need to reported that job to SCIP since the required bounds are already reported
2556  */
2557  if( inferpeak < ect && lst <= inferpeak )
2558  {
2559  capacity -= demands[j];
2560  reported[j] = TRUE;
2561 
2562  maxlst = MAX(maxlst, lst);
2563  minect = MIN(minect, ect);
2564  assert(maxlst < minect);
2565 
2566  if( explanation != NULL )
2567  explanation[j] = TRUE;
2568  }
2569  }
2570 
2571  if( capacity >= 0 )
2572  {
2573  int* cands;
2574  int* canddemands;
2575  int ncands;
2576  int c;
2577 
2578  SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2579  SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2580  ncands = 0;
2581 
2582  /* collect all cores of the variables which lay in the considered time window except the inference variable */
2583  for( j = 0; j < nvars; ++j )
2584  {
2585  var = vars[j];
2586  assert(var != NULL);
2587 
2588  /* skip inference variable */
2589  if( var == infervar || reported[j] )
2590  continue;
2591 
2592  duration = durations[j];
2593  assert(duration > 0);
2594 
2595  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2596  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2597  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2598  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2599  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2600 
2601  /* collect local core information */
2602  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2603  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2604 
2605  SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2606  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2607  SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2608 
2609  /* check if the inference peak is part of the core */
2610  if( inferpeak < ect && lst <= inferpeak )
2611  {
2612  cands[ncands] = j;
2613  canddemands[ncands] = demands[j];
2614  ncands++;
2615 
2616  capacity -= demands[j];
2617  }
2618  }
2619 
2620  /* sort candidates indices w.r.t. their demands */
2621  SCIPsortDownIntInt(canddemands, cands, ncands);
2622 
2623  assert(capacity < 0);
2624  assert(ncands > 0);
2625 
2626  /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2627  while( capacity + canddemands[ncands-1] < 0 )
2628  {
2629  ncands--;
2630  capacity += canddemands[ncands];
2631  assert(ncands > 0);
2632  }
2633 
2634  /* compute the size (number of time steps) of the job cores */
2635  for( c = 0; c < ncands; ++c )
2636  {
2637  var = vars[cands[c]];
2638  assert(var != NULL);
2639 
2640  duration = durations[cands[c]];
2641 
2642  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2643  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2644 
2645  maxlst = MAX(maxlst, lst);
2646  minect = MIN(minect, ect);
2647  assert(maxlst < minect);
2648  }
2649 
2650  SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2651  assert(inferpeak >= maxlst);
2652  assert(inferpeak < minect);
2653 
2654  /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2655  if( relaxedpeak < inferpeak )
2656  {
2657  inferpeak = MAX(maxlst, relaxedpeak);
2658  }
2659  else if( relaxedpeak > inferpeak )
2660  {
2661  inferpeak = MIN(minect-1, relaxedpeak);
2662  }
2663  assert(inferpeak >= hmin);
2664  assert(inferpeak < hmax);
2665  assert(inferpeak >= maxlst);
2666  assert(inferpeak < minect);
2667 
2668  /* post all necessary bound changes */
2669  for( c = 0; c < ncands; ++c )
2670  {
2671  var = vars[cands[c]];
2672  assert(var != NULL);
2673 
2674  if( usebdwidening )
2675  {
2676  duration = durations[cands[c]];
2677 
2678  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2679  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2680  }
2681  else
2682  {
2683  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2684  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2685  }
2686 
2687  if( explanation != NULL )
2688  explanation[cands[c]] = TRUE;
2689  }
2690 
2691  SCIPfreeBufferArray(scip, &canddemands);
2692  SCIPfreeBufferArray(scip, &cands);
2693  }
2694 
2695  SCIPfreeBufferArray(scip, &reported);
2696 
2697  if( provedpeak != NULL )
2698  *provedpeak = inferpeak;
2699 
2700  return SCIP_OKAY;
2701 }
2702 
2703 #if 0
2704 /** repropagation of edge finding algorithm simplified version from Petr Vilim only a small subset is reported such that
2705  * energy in total and for bound change is enough
2706  */
2707 static
2708 SCIP_RETCODE resolvePropagationEdgeFinding(
2709  SCIP* scip, /**< SCIP data structure */
2710  int nvars, /**< number of start time variables (activities) */
2711  SCIP_VAR** vars, /**< array of start time variables */
2712  int* durations, /**< array of durations */
2713  int hmin, /**< left bound of time axis to be considered (including hmin) */
2714  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2715  SCIP_VAR* infervar, /**< variable whose bound change is to be explained */
2716  INFERINFO inferinfo, /**< inference info containing position of correct bdchgids */
2717  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2718  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2719  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2720  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2721  )
2722 {
2723  int est;
2724  int lct;
2725  int j;
2726 
2727  /* ???????????????????? do bound widening */
2728 
2729  assert(scip != NULL);
2730  assert(nvars > 0);
2731  assert(inferInfoGetProprule(inferinfo) == PROPRULE_2_EDGEFINDING);
2732 
2733  SCIPdebugMsg(scip, "repropagate edge-finding with short reasons for variable <%s>\n", SCIPvarGetName(infervar));
2734 
2735  if( boundtype == SCIP_BOUNDTYPE_LOWER )
2736  {
2737  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
2738  }
2739  else
2740  {
2741  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
2742  }
2743 
2744  est = inferInfoGetData1(inferinfo);
2745  lct = inferInfoGetData2(inferinfo);
2746  assert(est < lct);
2747 
2748  /* collect the energies of all variables in [est_omega, lct_omega] */
2749  for( j = 0; j < nvars; ++j )
2750  {
2751  SCIP_VAR* var;
2752  SCIP_Bool left;
2753  SCIP_Bool right;
2754  int duration;
2755  int lb;
2756  int ub;
2757 
2758  var = vars[j];
2759  assert(var != NULL);
2760 
2761  if( var == infervar )
2762  {
2763  if( explanation != NULL )
2764  explanation[j] = TRUE;
2765 
2766  continue;
2767  }
2768 
2769  lb = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
2770  ub = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2771 
2772  duration = durations[j];
2773  assert(duration > 0);
2774 
2775  /* in case the earliest start time is equal to hmin we have to also consider the jobs which run in that region
2776  * since we use adjusted jobs during the propagation
2777  */
2778  left = (est == hmin && lb + duration > hmin) || lb >= est;
2779 
2780  /* in case the latest completion time is equal to hmax we have to also consider the jobs which run in that region
2781  * since we use adjusted jobs during the propagation
2782  */
2783  right = (lct == hmax && ub < hmax) || ub + duration <= lct;
2784 
2785  /* store all jobs running in [est_omega; lct_omega] */
2786  if( left && right )
2787  {
2788  /* check if bound widening should be used */
2789  if( usebdwidening )
2790  {
2791  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(lct - duration)) );
2792  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(est)) );
2793  }
2794  else
2795  {
2796  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2797  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2798  }
2799 
2800  if( explanation != NULL )
2801  explanation[j] = TRUE;
2802  }
2803  }
2804 
2805  return SCIP_OKAY;
2806 }
2807 #endif
2808 
2809 /** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2810 static
2811 int computeOverlap(
2812  int begin, /**< begin of the times interval */
2813  int end, /**< end of time interval */
2814  int est, /**< earliest start time */
2815  int lst, /**< latest start time */
2816  int duration /**< duration of the job */
2817  )
2818 {
2819  int left;
2820  int right;
2821  int ect;
2822  int lct;
2823 
2824  ect = est + duration;
2825  lct = lst + duration;
2826 
2827  /* check if job runs completely within [begin,end) */
2828  if( lct <= end && est >= begin )
2829  return duration;
2830 
2831  assert(lst <= end && ect >= begin);
2832 
2833  left = ect - begin;
2834  assert(left > 0);
2835 
2836  right = end - lst;
2837  assert(right > 0);
2838 
2839  return MIN3(left, right, end - begin);
2840 }
2841 
2842 /** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2843  * reason
2844  *
2845  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2846  */
2847 static
2849  SCIP* scip, /**< SCIP data structure */
2850  int nvars, /**< number of start time variables (activities) */
2851  SCIP_VAR** vars, /**< array of start time variables */
2852  int* durations, /**< array of durations */
2853  int* demands, /**< array of demands */
2854  int capacity, /**< capacity of the cumulative condition */
2855  int begin, /**< begin of the time window */
2856  int end, /**< end of the time window */
2857  SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2858  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2859  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2860  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2861  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2862  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2863  )
2864 {
2865  int* locenergies;
2866  int* overlaps;
2867  int* idxs;
2868 
2869  SCIP_Longint requiredenergy;
2870  int v;
2871 
2872  SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2873  SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2874  SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2875 
2876  /* energy which needs be explained */
2877  requiredenergy = ((SCIP_Longint) end - begin) * capacity;
2878 
2879  SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %d)\n", begin, end, capacity, requiredenergy);
2880 
2881  /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2882  * takes
2883  */
2884  for( v = 0; v < nvars; ++v )
2885  {
2886  SCIP_VAR* var;
2887  int glbenergy;
2888  int duration;
2889  int demand;
2890  int est;
2891  int lst;
2892 
2893  var = vars[v];
2894  assert(var != NULL);
2895 
2896  locenergies[v] = 0;
2897  overlaps[v] = 0;
2898  idxs[v] = v;
2899 
2900  demand = demands[v];
2901  assert(demand > 0);
2902 
2903  duration = durations[v];
2904  assert(duration > 0);
2905 
2906  /* check if the variable equals the inference variable (the one which was propagated) */
2907  if( infervar == var )
2908  {
2909  int overlap;
2910  int right;
2911  int left;
2912 
2913  assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2914 
2915  SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2916  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2917  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2918 
2919  /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2920  * which is necessary from the inference variable
2921  */
2922  if( boundtype == SCIP_BOUNDTYPE_UPPER )
2923  {
2924  int lct;
2925 
2926  /* get the latest start time of the infer start time variable before the propagation took place */
2927  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2928 
2929  /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2930  * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2931  * scheduled w.r.t. its latest start time
2932  */
2933  assert(lst < end);
2934 
2935  /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2936  * interval (before the propagation)
2937  */
2938  right = MIN3(end - lst, end - begin, duration);
2939 
2940  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2941  assert(right > 0);
2942 
2943  lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2944  assert(begin <= lct);
2945  assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
2946 
2947  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2948  left = MIN(lct - begin + 1, end - begin);
2949  assert(left > 0);
2950 
2951  /* compute the minimum overlap; */
2952  overlap = MIN(left, right);
2953  assert(overlap > 0);
2954  assert(overlap <= end - begin);
2955  assert(overlap <= duration);
2956 
2957  if( usebdwidening )
2958  {
2959  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2960  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2961  }
2962  else
2963  {
2964  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2965  }
2966  }
2967  else
2968  {
2969  int ect;
2970 
2971  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2972 
2973  /* get the earliest completion time of the infer start time variable before the propagation took place */
2974  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2975 
2976  /* the earliest start time of the inference start time variable before the propagation needs to be larger as
2977  * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
2978  * the job is scheduled w.r.t. its earliest start time
2979  */
2980  assert(ect > begin);
2981 
2982  /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
2983  * interval (before the propagation)
2984  */
2985  left = MIN3(ect - begin, end - begin, duration);
2986 
2987  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2988  assert(left > 0);
2989 
2990  est = SCIPconvertRealToInt(scip, relaxedbd);
2991  assert(end >= est);
2992  assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
2993 
2994  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2995  right = MIN(end - est + 1, end - begin);
2996  assert(right > 0);
2997 
2998  /* compute the minimum overlap */
2999  overlap = MIN(left, right);
3000  assert(overlap > 0);
3001  assert(overlap <= end - begin);
3002  assert(overlap <= duration);
3003 
3004  if( usebdwidening )
3005  {
3006  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
3007  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
3008  }
3009  else
3010  {
3011  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
3012  }
3013  }
3014 
3015  /* subtract the amount of energy which is available due to the overlap of the inference start time */
3016  requiredenergy -= (SCIP_Longint) overlap * demand;
3017 
3018  if( explanation != NULL )
3019  explanation[v] = TRUE;
3020 
3021  continue;
3022  }
3023 
3024  /* global time points */
3025  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
3026  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
3027 
3028  glbenergy = 0;
3029 
3030  /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
3031  * time window
3032  */
3033  if( est + duration > begin && lst < end )
3034  {
3035  /* evaluated global contribution */
3036  glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
3037 
3038  /* remove the globally available energy form the required energy */
3039  requiredenergy -= glbenergy;
3040 
3041  if( explanation != NULL )
3042  explanation[v] = TRUE;
3043  }
3044 
3045  /* local time points */
3046  est = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
3047  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
3048 
3049  /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3050  * time window
3051  */
3052  if( est + duration > begin && lst < end )
3053  {
3054  overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3055 
3056  /* evaluated additionally local energy contribution */
3057  locenergies[v] = overlaps[v] * demand - glbenergy;
3058  assert(locenergies[v] >= 0);
3059  }
3060  }
3061 
3062  /* sort the variable contributions w.r.t. additional local energy contributions */
3063  SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3064 
3065  /* add local energy contributions until an overload is implied */
3066  for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3067  {
3068  SCIP_VAR* var;
3069  int duration;
3070  int overlap;
3071  int relaxlb;
3072  int relaxub;
3073  int idx;
3074 
3075  idx = idxs[v];
3076  assert(idx >= 0 && idx < nvars);
3077 
3078  var = vars[idx];
3079  assert(var != NULL);
3080  assert(var != infervar);
3081 
3082  duration = durations[idx];
3083  assert(duration > 0);
3084 
3085  overlap = overlaps[v];
3086  assert(overlap > 0);
3087 
3088  requiredenergy -= locenergies[v];
3089 
3090  if( requiredenergy < -1 )
3091  {
3092  int demand;
3093 
3094  demand = demands[idx];
3095  assert(demand > 0);
3096 
3097  overlap += (int)((requiredenergy + 1) / demand);
3098 
3099 #ifndef NDEBUG
3100  requiredenergy += locenergies[v];
3101  requiredenergy -= (SCIP_Longint) overlap * demand;
3102  assert(requiredenergy < 0);
3103 #endif
3104  }
3105  assert(overlap > 0);
3106 
3107  relaxlb = begin - duration + overlap;
3108  relaxub = end - overlap;
3109 
3110  SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3111  SCIPvarGetName(var),
3114  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var),
3115  relaxlb, relaxub, demands[idx], duration);
3116 
3117  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3118  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3119 
3120  if( explanation != NULL )
3121  explanation[idx] = TRUE;
3122  }
3123 
3124  assert(requiredenergy < 0);
3125 
3126  SCIPfreeBufferArray(scip, &idxs);
3127  SCIPfreeBufferArray(scip, &overlaps);
3128  SCIPfreeBufferArray(scip, &locenergies);
3129 
3130  return SCIP_OKAY;
3131 }
3132 
3133 /** resolve propagation w.r.t. the cumulative condition */
3134 static
3136  SCIP* scip, /**< SCIP data structure */
3137  int nvars, /**< number of start time variables (activities) */
3138  SCIP_VAR** vars, /**< array of start time variables */
3139  int* durations, /**< array of durations */
3140  int* demands, /**< array of demands */
3141  int capacity, /**< cumulative capacity */
3142  int hmin, /**< left bound of time axis to be considered (including hmin) */
3143  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3144  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3145  INFERINFO inferinfo, /**< the user information */
3146  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3147  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3148  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3149  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3150  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3151  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3152  )
3153 {
3154  switch( inferInfoGetProprule(inferinfo) )
3155  {
3156  case PROPRULE_1_CORETIMES:
3157  {
3158  int inferdemand;
3159  int inferduration;
3160  int inferpos;
3161  int inferpeak;
3162  int relaxedpeak;
3163  int provedpeak;
3164 
3165  /* get the position of the inferred variable in the vars array */
3166  inferpos = inferInfoGetData1(inferinfo);
3167  if( inferpos >= nvars || vars[inferpos] != infervar )
3168  {
3169  /* find inference variable in constraint */
3170  for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3171  {}
3172  }
3173  assert(inferpos < nvars);
3174  assert(vars[inferpos] == infervar);
3175 
3176  inferdemand = demands[inferpos];
3177  inferduration = durations[inferpos];
3178 
3179  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3180  {
3181  /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3182  * the inference variable
3183  */
3184  assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
3185 
3186  SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3187  SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
3188  SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3189 
3190  /* get the inference peak that the time point which lead to the that propagtion */
3191  inferpeak = inferInfoGetData2(inferinfo);
3192  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3193  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3194  */
3195  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3196  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) + inferduration;
3197 
3198  /* make sure that the relaxed peak is part of the effective horizon */
3199  relaxedpeak = MIN(relaxedpeak, hmax-1);
3200 
3201  /* make sure that relaxed peak is not larger than the infer peak
3202  *
3203  * This can happen in case the variable is not an active variable!
3204  */
3205  relaxedpeak = MAX(relaxedpeak, inferpeak);
3206  assert(relaxedpeak >= inferpeak);
3207  assert(relaxedpeak >= hmin);
3208  }
3209  else
3210  {
3211  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3212 
3213  SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3214  SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
3215  SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3216 
3217  /* get the time interval where the job could not be scheduled */
3218  inferpeak = inferInfoGetData2(inferinfo);
3219  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3220  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3221  */
3222  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3223  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) - 1;
3224 
3225  /* make sure that the relaxed peak is part of the effective horizon */
3226  relaxedpeak = MAX(relaxedpeak, hmin);
3227 
3228  /* make sure that relaxed peak is not larger than the infer peak
3229  *
3230  * This can happen in case the variable is not an active variable!
3231  */
3232  relaxedpeak = MIN(relaxedpeak, inferpeak);
3233  assert(relaxedpeak < hmax);
3234  }
3235 
3236  /* resolves the propagation of the core time algorithm */
3237  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3238  infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3239 
3240  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3241  {
3242  if( usebdwidening )
3243  {
3244  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3245  }
3246  else
3247  {
3248  /* old upper bound of variable itself is part of the explanation */
3249  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3250  }
3251  }
3252  else
3253  {
3254  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3255 
3256  if( usebdwidening )
3257  {
3258  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3259  }
3260  else
3261  {
3262  /* old lower bound of variable itself is part of the explanation */
3263  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3264  }
3265  }
3266 
3267  if( explanation != NULL )
3268  explanation[inferpos] = TRUE;
3269 
3270  break;
3271  }
3273  case PROPRULE_3_TTEF:
3274  {
3275  int begin;
3276  int end;
3277 
3278  begin = inferInfoGetData1(inferinfo);
3279  end = inferInfoGetData2(inferinfo);
3280  assert(begin < end);
3281 
3282  begin = MAX(begin, hmin);
3283  end = MIN(end, hmax);
3284 
3285  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3286  begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3287 
3288  break;
3289  }
3290 
3291  default:
3292  SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3293  SCIPABORT();
3294  return SCIP_INVALIDDATA; /*lint !e527*/
3295  }
3296 
3297  (*result) = SCIP_SUCCESS;
3298 
3299  return SCIP_OKAY;
3300 }
3301 
3302 /**@} */
3303 
3304 
3305 /**@name Enforcement methods
3306  *
3307  * @{
3308  */
3309 
3310 /** apply all fixings which are given by the alternative bounds */
3311 static
3313  SCIP* scip, /**< SCIP data structure */
3314  SCIP_VAR** vars, /**< array of active variables */
3315  int nvars, /**< number of active variables */
3316  int* alternativelbs, /**< alternative lower bounds */
3317  int* alternativeubs, /**< alternative lower bounds */
3318  int* downlocks, /**< number of constraints with down lock participating by the computation */
3319  int* uplocks, /**< number of constraints with up lock participating by the computation */
3320  SCIP_Bool* branched /**< pointer to store if a branching was applied */
3321  )
3322 {
3323  int v;
3324 
3325  for( v = 0; v < nvars; ++v )
3326  {
3327  SCIP_VAR* var;
3328  SCIP_Real objval;
3329 
3330  var = vars[v];
3331  assert(var != NULL);
3332 
3333  objval = SCIPvarGetObj(var);
3334 
3335  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] && !SCIPisNegative(scip, objval) )
3336  {
3337  int ub;
3338 
3339  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3340 
3341  if( alternativelbs[v] <= ub )
3342  {
3343  SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3344  (*branched) = TRUE;
3345 
3346  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3347  SCIPvarGetLbLocal(var), alternativelbs[v]);
3348 
3349  return SCIP_OKAY;
3350  }
3351  }
3352 
3353  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] && !SCIPisPositive(scip, objval) )
3354  {
3355  int lb;
3356 
3357  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3358 
3359  if( alternativeubs[v] >= lb )
3360  {
3361  SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3362  (*branched) = TRUE;
3363 
3364  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3365  alternativeubs[v], SCIPvarGetUbLocal(var));
3366 
3367  return SCIP_OKAY;
3368  }
3369  }
3370  }
3371 
3372  return SCIP_OKAY;
3373 }
3374 
3375 /** remove the capacity requirments for all job which start at the curtime */
3376 static
3378  SCIP_CONSDATA* consdata, /**< constraint data */
3379  int curtime, /**< current point in time */
3380  int* starttimes, /**< array of start times */
3381  int* startindices, /**< permutation with respect to the start times */
3382  int* freecapacity, /**< pointer to store the resulting free capacity */
3383  int* idx, /**< pointer to index in start time array */
3384  int nvars /**< number of vars in array of starttimes and startindices */
3385  )
3386 {
3387 #if defined SCIP_DEBUG && !defined NDEBUG
3388  int oldidx;
3389 
3390  assert(idx != NULL);
3391  oldidx = *idx;
3392 #else
3393  assert(idx != NULL);
3394 #endif
3395 
3396  assert(starttimes != NULL);
3397  assert(starttimes != NULL);
3398  assert(freecapacity != NULL);
3399  assert(starttimes[*idx] == curtime);
3400  assert(consdata->demands != NULL);
3401  assert(freecapacity != idx);
3402 
3403  /* subtract all capacity needed up to this point */
3404  (*freecapacity) -= consdata->demands[startindices[*idx]];
3405 
3406  while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3407  {
3408  ++(*idx);
3409  (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3410  assert(freecapacity != idx);
3411  }
3412 #ifdef SCIP_DEBUG
3413  assert(oldidx <= *idx);
3414 #endif
3415 }
3416 
3417 /** add the capacity requirments for all job which end at the curtime */
3418 static
3419 void addEndingJobDemands(
3420  SCIP_CONSDATA* consdata, /**< constraint data */
3421  int curtime, /**< current point in time */
3422  int* endtimes, /**< array of end times */
3423  int* endindices, /**< permutation with rspect to the end times */
3424  int* freecapacity, /**< pointer to store the resulting free capacity */
3425  int* idx, /**< pointer to index in end time array */
3426  int nvars /**< number of vars in array of starttimes and startindices */
3427  )
3428 {
3429 #if defined SCIP_DEBUG && !defined NDEBUG
3430  int oldidx;
3431  oldidx = *idx;
3432 #endif
3433 
3434  /* free all capacity usages of jobs the are no longer running */
3435  while( endtimes[*idx] <= curtime && *idx < nvars)
3436  {
3437  (*freecapacity) += consdata->demands[endindices[*idx]];
3438  ++(*idx);
3439  }
3440 
3441 #ifdef SCIP_DEBUG
3442  assert(oldidx <= *idx);
3443 #endif
3444 }
3445 
3446 /** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3447 static
3449  SCIP* scip, /**< SCIP data structure */
3450  SCIP_CONSDATA* consdata, /**< constraint handler data */
3451  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3452  int* timepoint /**< pointer to store the time point of the peak */
3453  )
3454 {
3455  int* starttimes; /* stores when each job is starting */
3456  int* endtimes; /* stores when each job ends */
3457  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3458  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3459 
3460  int nvars; /* number of activities for this constraint */
3461  int freecapacity; /* remaining capacity */
3462  int curtime; /* point in time which we are just checking */
3463  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3464 
3465  int hmin;
3466  int hmax;
3467 
3468  int j;
3469 
3470  assert(consdata != NULL);
3471 
3472  nvars = consdata->nvars;
3473  assert(nvars > 0);
3474 
3475  *timepoint = consdata->hmax;
3476 
3477  assert(consdata->vars != NULL);
3478 
3479  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3480  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3481  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3482  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3483 
3484  /* create event point arrays */
3485  createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3486  starttimes, endtimes, startindices, endindices);
3487 
3488  endindex = 0;
3489  freecapacity = consdata->capacity;
3490  hmin = consdata->hmin;
3491  hmax = consdata->hmax;
3492 
3493  /* check each startpoint of a job whether the capacity is kept or not */
3494  for( j = 0; j < nvars; ++j )
3495  {
3496  curtime = starttimes[j];
3497  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3498 
3499  if( curtime >= hmax )
3500  break;
3501 
3502  /* remove the capacity requirments for all job which start at the curtime */
3503  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3504 
3505  /* add the capacity requirments for all job which end at the curtime */
3506  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3507 
3508  assert(freecapacity <= consdata->capacity);
3509  assert(endindex <= nvars);
3510 
3511  /* endindex - points to the next job which will finish */
3512  /* j - points to the last job that has been released */
3513 
3514  /* if free capacity is smaller than zero, then add branching candidates */
3515  if( freecapacity < 0 && curtime >= hmin )
3516  {
3517  *timepoint = curtime;
3518  break;
3519  }
3520  } /*lint --e{850}*/
3521 
3522  /* free all buffer arrays */
3523  SCIPfreeBufferArray(scip, &endindices);
3524  SCIPfreeBufferArray(scip, &startindices);
3525  SCIPfreeBufferArray(scip, &endtimes);
3526  SCIPfreeBufferArray(scip, &starttimes);
3527 
3528  return SCIP_OKAY;
3529 }
3530 
3531 /** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3532 static
3534  SCIP* scip, /**< SCIP data structure */
3535  SCIP_CONS** conss, /**< constraints to be processed */
3536  int nconss, /**< number of constraints */
3537  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3538  int* nbranchcands /**< pointer to store the number of branching variables */
3539  )
3540 {
3541  SCIP_HASHTABLE* collectedvars;
3542  int c;
3543 
3544  assert(scip != NULL);
3545  assert(conss != NULL);
3546 
3547  /* create a hash table */
3548  SCIP_CALL( SCIPhashtableCreate(&collectedvars, SCIPblkmem(scip), SCIPgetNVars(scip),
3549  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3550 
3551  assert(scip != NULL);
3552  assert(conss != NULL);
3553 
3554  for( c = 0; c < nconss; ++c )
3555  {
3556  SCIP_CONS* cons;
3557  SCIP_CONSDATA* consdata;
3558 
3559  int curtime;
3560  int j;
3561 
3562  cons = conss[c];
3563  assert(cons != NULL);
3564 
3565  if( !SCIPconsIsActive(cons) )
3566  continue;
3567 
3568  consdata = SCIPconsGetData(cons);
3569  assert(consdata != NULL);
3570 
3571  /* get point in time when capacity is exceeded */
3572  SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3573 
3574  if( curtime < consdata->hmin || curtime >= consdata->hmax )
3575  continue;
3576 
3577  /* report all variables that are running at that point in time */
3578  for( j = 0; j < consdata->nvars; ++j )
3579  {
3580  SCIP_VAR* var;
3581  int lb;
3582  int ub;
3583 
3584  var = consdata->vars[j];
3585  assert(var != NULL);
3586 
3587  /* check if the variable was already added */
3588  if( SCIPhashtableExists(collectedvars, (void*)var) )
3589  continue;
3590 
3591  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3592  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3593 
3594  if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3595  {
3596  SCIP_Real solval;
3597  SCIP_Real score;
3598 
3599  solval = SCIPgetSolVal(scip, sol, var);
3600  score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3601 
3602  SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3603  SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3604  (*nbranchcands)++;
3605 
3606  SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3607  }
3608  }
3609  }
3610 
3611  SCIPhashtableFree(&collectedvars);
3612 
3613  SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3614 
3615  return SCIP_OKAY;
3616 }
3617 
3618 /** enforcement of an LP, pseudo, or relaxation solution */
3619 static
3621  SCIP* scip, /**< SCIP data structure */
3622  SCIP_CONS** conss, /**< constraints to be processed */
3623  int nconss, /**< number of constraints */
3624  SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
3625  SCIP_Bool branch, /**< should branching candidates be collected */
3626  SCIP_RESULT* result /**< pointer to store the result */
3627  )
3628 {
3629  if( branch )
3630  {
3631  int nbranchcands;
3632 
3633  nbranchcands = 0;
3634  SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3635 
3636  if( nbranchcands > 0 )
3637  (*result) = SCIP_INFEASIBLE;
3638  }
3639  else
3640  {
3641  SCIP_Bool violated;
3642  int c;
3643 
3644  violated = FALSE;
3645 
3646  /* first check if a constraints is violated */
3647  for( c = 0; c < nconss && !violated; ++c )
3648  {
3649  SCIP_CONS* cons;
3650 
3651  cons = conss[c];
3652  assert(cons != NULL);
3653 
3654  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3655  }
3656 
3657  if( violated )
3658  (*result) = SCIP_INFEASIBLE;
3659  }
3660 
3661  return SCIP_OKAY;
3662 }
3663 
3664 /**@} */
3665 
3666 /**@name Propagation
3667  *
3668  * @{
3669  */
3670 
3671 /** check if cumulative constraint is independently of all other constraints */
3672 static
3674  SCIP_CONS* cons /**< cumulative constraint */
3675  )
3676 {
3677  SCIP_CONSDATA* consdata;
3678  SCIP_VAR** vars;
3679  SCIP_Bool* downlocks;
3680  SCIP_Bool* uplocks;
3681  int nvars;
3682  int v;
3683 
3684  consdata = SCIPconsGetData(cons);
3685  assert(consdata != NULL);
3686 
3687  nvars = consdata->nvars;
3688  vars = consdata->vars;
3689  downlocks = consdata->downlocks;
3690  uplocks = consdata->uplocks;
3691 
3692  /* check if the cumulative constraint has the only locks on the involved variables */
3693  for( v = 0; v < nvars; ++v )
3694  {
3695  SCIP_VAR* var;
3696 
3697  var = vars[v];
3698  assert(var != NULL);
3699 
3700  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
3701  || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
3702  return FALSE;
3703  }
3704 
3705  return TRUE;
3706 }
3707 
3708 /** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3709  * (dual reductions)
3710  */
3711 static
3713  SCIP* scip, /**< SCIP data structure */
3714  SCIP_CONS* cons, /**< cumulative constraint */
3715  SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3716  int* nchgbds, /**< pointer to store the number changed variable bounds */
3717  int* nfixedvars, /**< pointer to count number of fixings */
3718  int* ndelconss, /**< pointer to count number of deleted constraints */
3719  SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3720  SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3721  )
3722 {
3723  SCIP_CONSDATA* consdata;
3724  SCIP_VAR** vars;
3725  SCIP_Real* objvals;
3726  SCIP_Real* lbs;
3727  SCIP_Real* ubs;
3728  SCIP_Real timelimit;
3729  SCIP_Real memorylimit;
3730  SCIP_Bool solved;
3731  SCIP_Bool error;
3732 
3733  int ncheckconss;
3734  int nvars;
3735  int v;
3736 
3737  assert(scip != NULL);
3738  assert(!SCIPconsIsModifiable(cons));
3739  assert(SCIPgetNConss(scip) > 0);
3740 
3741  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3742  * would/could end in an implication which can lead to cutoff of the/all optimal solution
3743  */
3744  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
3745  return SCIP_OKAY;
3746 
3747  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3748  * use the locks to decide for a dual reduction using this constraint;
3749  */
3750  if( !SCIPconsIsChecked(cons) )
3751  return SCIP_OKAY;
3752 
3753  ncheckconss = SCIPgetNCheckConss(scip);
3754 
3755  /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3756  * presolved problem do nothing execpt to change the parameter settings
3757  */
3758  if( ncheckconss == 1 )
3759  {
3760  /* shrink the minimal maximum value for the conflict length */
3761  SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3762 
3763  /* use only first unique implication point */
3764  SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3765 
3766  /* do not use reconversion conflicts */
3767  SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3768 
3769  /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3770  SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3771 
3772  /* increase the number of conflicts which induce a restart */
3773  SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3774 
3775  /* weight the variable which made into a conflict */
3776  SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3777 
3778  /* do not check pseudo solution (for performance reasons) */
3779  SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3780 
3781  /* use value based history to detect a reasonable branching point */
3782  SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3783 
3784  /* turn of LP relaxation */
3785  SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3786 
3787  /* prefer the down branch in case the value based history does not suggest something */
3788  SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3789 
3790  /* accept any bound change */
3791  SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3792 
3793  /* allow for at most 10 restart, after that the value based history should be reliable */
3794  SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3795 
3796  /* set priority for depth first search to highest possible value */
3797  SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3798 
3799  return SCIP_OKAY;
3800  }
3801 
3802  consdata = SCIPconsGetData(cons);
3803  assert(consdata != NULL);
3804 
3805  /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3806  * fail on the first place
3807  */
3808  if( consdata->triedsolving )
3809  return SCIP_OKAY;
3810 
3811  /* check if constraint is independently */
3812  if( !isConsIndependently(cons) )
3813  return SCIP_OKAY;
3814 
3815  /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3816  * constraint is deleted; otherwise, we want to ensure that we do not try that again
3817  */
3818  consdata->triedsolving = TRUE;
3819 
3820  SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3821  SCIPconsGetName(cons), SCIPgetNVars(scip), SCIPgetNConss(scip));
3822  SCIPdebugPrintCons(scip, cons, NULL);
3823 
3824  nvars = consdata->nvars;
3825  vars = consdata->vars;
3826 
3827  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3828  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3829  SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3830 
3831  for( v = 0; v < nvars; ++v )
3832  {
3833  SCIP_VAR* var;
3834 
3835  /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3836  * array
3837  */
3838  var = vars[v];
3839  assert(var != NULL);
3840 
3841  lbs[v] = SCIPvarGetLbLocal(var);
3842  ubs[v] = SCIPvarGetUbLocal(var);
3843 
3844  objvals[v] = SCIPvarGetObj(var);
3845  }
3846 
3847  /* check whether there is enough time and memory left */
3848  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3849  if( !SCIPisInfinity(scip, timelimit) )
3850  timelimit -= SCIPgetSolvingTime(scip);
3851  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3852 
3853  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3854  if( !SCIPisInfinity(scip, memorylimit) )
3855  {
3856  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3857  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3858  }
3859 
3860  /* solve the cumulative condition separately */
3861  SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3862  consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3863 
3864  if( !(*cutoff) && !(*unbounded) && !error )
3865  {
3866  SCIP_Bool infeasible;
3867  SCIP_Bool tightened;
3868  SCIP_Bool allfixed;
3869 
3870  allfixed = TRUE;
3871 
3872  for( v = 0; v < nvars; ++v )
3873  {
3874  /* check if variable is fixed */
3875  if( lbs[v] + 0.5 > ubs[v] )
3876  {
3877  SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3878  assert(!infeasible);
3879 
3880  if( tightened )
3881  {
3882  (*nfixedvars)++;
3883  consdata->triedsolving = FALSE;
3884  }
3885  }
3886  else
3887  {
3888  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3889  assert(!infeasible);
3890 
3891  if( tightened )
3892  {
3893  (*nchgbds)++;
3894  consdata->triedsolving = FALSE;
3895  }
3896 
3897  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3898  assert(!infeasible);
3899 
3900  if( tightened )
3901  {
3902  (*nchgbds)++;
3903  consdata->triedsolving = FALSE;
3904  }
3905 
3906  allfixed = FALSE;
3907  }
3908  }
3909 
3910  /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3911  if( allfixed )
3912  {
3913  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3914  (*ndelconss)++;
3915  }
3916  }
3917 
3918  SCIPfreeBufferArray(scip, &objvals);
3919  SCIPfreeBufferArray(scip, &ubs);
3920  SCIPfreeBufferArray(scip, &lbs);
3921 
3922  return SCIP_OKAY;
3923 }
3924 
3925 /** start conflict analysis to analysis the core insertion which is infeasible */
3926 static
3928  SCIP* scip, /**< SCIP data structure */
3929  int nvars, /**< number of start time variables (activities) */
3930  SCIP_VAR** vars, /**< array of start time variables */
3931  int* durations, /**< array of durations */
3932  int* demands, /**< array of demands */
3933  int capacity, /**< cumulative capacity */
3934  int hmin, /**< left bound of time axis to be considered (including hmin) */
3935  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3936  SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3937  int inferduration, /**< duration of the start time variable */
3938  int inferdemand, /**< demand of the start time variable */
3939  int inferpeak, /**< profile preak which causes the infeasibilty */
3940  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3941  SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3942  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3943  )
3944 {
3945  SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3946  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3947  SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3948 
3949  /* initialize conflict analysis if conflict analysis is applicable */
3951  {
3953 
3954  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3955  infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3956 
3957  SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3958 
3959  /* add both bound of the inference variable since these biuld the core which we could not inserted */
3960  if( usebdwidening )
3961  {
3962  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
3963  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
3964  }
3965  else
3966  {
3967  SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
3968  SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
3969  }
3970 
3971  *initialized = TRUE;
3972  }
3973 
3974  return SCIP_OKAY;
3975 }
3976 
3977 /** We are using the core resource profile which contains all core except the one of the start time variable which we
3978  * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
3979  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
3980  * analysis
3981  */
3982 static
3984  SCIP* scip, /**< SCIP data structure */
3985  int nvars, /**< number of start time variables (activities) */
3986  SCIP_VAR** vars, /**< array of start time variables */
3987  int* durations, /**< array of durations */
3988  int* demands, /**< array of demands */
3989  int capacity, /**< cumulative capacity */
3990  int hmin, /**< left bound of time axis to be considered (including hmin) */
3991  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3992  SCIP_CONS* cons, /**< constraint which is propagated */
3993  SCIP_PROFILE* profile, /**< resource profile */
3994  int idx, /**< position of the variable to propagate */
3995  int* nchgbds, /**< pointer to store the number of bound changes */
3996  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3997  SCIP_Bool* initialized, /**< was conflict analysis initialized */
3998  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3999  SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
4000  )
4001 {
4002  SCIP_VAR* var;
4003  int ntimepoints;
4004  int duration;
4005  int demand;
4006  int peak;
4007  int newlb;
4008  int est;
4009  int lst;
4010  int pos;
4011 
4012  var = vars[idx];
4013  assert(var != NULL);
4014 
4015  duration = durations[idx];
4016  assert(duration > 0);
4017 
4018  demand = demands[idx];
4019  assert(demand > 0);
4020 
4021  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4022  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4023  ntimepoints = SCIPprofileGetNTimepoints(profile);
4024 
4025  /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
4026  * load which we have at the earliest start time (lower bound)
4027  */
4028  (void) SCIPprofileFindLeft(profile, est, &pos);
4029 
4030  SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
4031 
4032  /* we now trying to move the earliest start time in steps of at most "duration" length */
4033  do
4034  {
4035  INFERINFO inferinfo;
4036  SCIP_Bool tightened;
4037  int ect;
4038 
4039 #ifndef NDEBUG
4040  {
4041  /* in debug mode we check that we adjust the search position correctly */
4042  int tmppos;
4043 
4044  (void)SCIPprofileFindLeft(profile, est, &tmppos);
4045  assert(pos == tmppos);
4046  }
4047 #endif
4048  ect = est + duration;
4049  peak = -1;
4050 
4051  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4052  * want a peak which is closest to the earliest completion time
4053  */
4054  do
4055  {
4056  /* check if the profile load conflicts with the demand of the start time variable */
4057  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4058  peak = pos;
4059 
4060  pos++;
4061  }
4062  while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4063 
4064  /* if we found no peak that means current the job could be scheduled at its earliest start time without
4065  * conflicting to the core resource profile
4066  */
4067  if( peak == -1 )
4068  break;
4069 
4070  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4071  * profile. That means we have to move it to the next time point in the resource profile but at most to the
4072  * earliest completion time (the remaining move will done in the next loop)
4073  */
4074  newlb = SCIPprofileGetTime(profile, peak+1);
4075  newlb = MIN(newlb, ect);
4076 
4077  /* if the earliest start time is greater than the lst we detected an infeasibilty */
4078  if( newlb > lst )
4079  {
4080  SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4081 
4082  /* use conflict analysis to analysis the core insertion which was infeasible */
4083  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4084  var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4085 
4086  if( explanation != NULL )
4087  explanation[idx] = TRUE;
4088 
4089  *infeasible = TRUE;
4090 
4091  break;
4092  }
4093 
4094  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4095  * bound change
4096  */
4097  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4098 
4099  /* perform the bound lower bound change */
4100  SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4101  assert(tightened);
4102  assert(!(*infeasible));
4103 
4104  SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4105  (*nchgbds)++;
4106 
4107  /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4109 
4110  /* adjust the earliest start time
4111  *
4112  * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4113  * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4114  * involved.
4115  */
4116  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4117  assert(est >= newlb);
4118 
4119  /* adjust the search position for the resource profile for the next step */
4120  if( est == SCIPprofileGetTime(profile, peak+1) )
4121  pos = peak + 1;
4122  else
4123  pos = peak;
4124  }
4125  while( est < lst );
4126 
4127  return SCIP_OKAY;
4128 }
4129 
4130 /** We are using the core resource profile which contains all core except the one of the start time variable which we
4131  * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4132  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4133  * analysis
4134  */
4135 static
4137  SCIP* scip, /**< SCIP data structure */
4138  SCIP_VAR* var, /**< start time variable to propagate */
4139  int duration, /**< duration of the job */
4140  int demand, /**< demand of the job */
4141  int capacity, /**< cumulative capacity */
4142  SCIP_CONS* cons, /**< constraint which is propagated */
4143  SCIP_PROFILE* profile, /**< resource profile */
4144  int idx, /**< position of the variable to propagate */
4145  int* nchgbds /**< pointer to store the number of bound changes */
4146  )
4147 {
4148  int ntimepoints;
4149  int newub;
4150  int peak;
4151  int pos;
4152  int est;
4153  int lst;
4154  int lct;
4155 
4156  assert(var != NULL);
4157  assert(duration > 0);
4158  assert(demand > 0);
4159 
4160  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4161  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4162 
4163  /* in case the start time variable is fixed do nothing */
4164  if( est == lst )
4165  return SCIP_OKAY;
4166 
4167  ntimepoints = SCIPprofileGetNTimepoints(profile);
4168 
4169  lct = lst + duration;
4170 
4171  /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4172  * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4173  * position gives us the load which we have at the latest completion time minus one
4174  */
4175  (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4176 
4177  SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4178  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
4179 
4180  if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4181  return SCIP_OKAY;
4182 
4183  /* we now trying to move the latest start time in steps of at most "duration" length */
4184  do
4185  {
4186  INFERINFO inferinfo;
4187  SCIP_Bool tightened;
4188  SCIP_Bool infeasible;
4189 
4190  peak = -1;
4191 
4192 #ifndef NDEBUG
4193  {
4194  /* in debug mode we check that we adjust the search position correctly */
4195  int tmppos;
4196 
4197  (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4198  assert(pos == tmppos);
4199  }
4200 #endif
4201 
4202  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4203  * want a peak which is closest to the latest start time
4204  */
4205  do
4206  {
4207  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4208  peak = pos;
4209 
4210  pos--;
4211  }
4212  while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4213 
4214  /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4215  * to the core resource profile
4216  */
4217  if( peak == -1 )
4218  break;
4219 
4220  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4221  * profile. That means the job has be done until that point. Hence that gives us the latest completion
4222  * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4223  * doing in the next loop)
4224  */
4225  newub = SCIPprofileGetTime(profile, peak);
4226  newub = MAX(newub, lst) - duration;
4227  assert(newub >= est);
4228 
4229  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4230  * bound change
4231  */
4232  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4233 
4234  /* perform the bound upper bound change */
4235  SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4236  assert(tightened);
4237  assert(!infeasible);
4238 
4239  SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4240  (*nchgbds)++;
4241 
4242  /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4244 
4245  /* adjust the latest start and completion time
4246  *
4247  * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4248  * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4249  * involved.
4250  */
4251  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4252  assert(lst <= newub);
4253  lct = lst + duration;
4254 
4255  /* adjust the search position for the resource profile for the next step */
4256  if( SCIPprofileGetTime(profile, peak) == lct )
4257  pos = peak - 1;
4258  else
4259  pos = peak;
4260  }
4261  while( est < lst );
4262 
4263  return SCIP_OKAY;
4264 }
4265 
4266 /** compute for the different earliest start and latest completion time the core energy of the corresponding time
4267  * points
4268  */
4269 static
4271  SCIP_PROFILE* profile, /**< core profile */
4272  int nvars, /**< number of start time variables (activities) */
4273  int* ests, /**< array of sorted earliest start times */
4274  int* lcts, /**< array of sorted latest completion times */
4275  int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4276  int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4277  )
4278 {
4279  int ntimepoints;
4280  int energy;
4281  int t;
4282  int v;
4283 
4284  ntimepoints = SCIPprofileGetNTimepoints(profile);
4285  t = ntimepoints - 1;
4286  energy = 0;
4287 
4288  /* compute core energy after the earliest start time of each job */
4289  for( v = nvars-1; v >= 0; --v )
4290  {
4291  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4292  {
4293  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4294  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4295  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4296  t--;
4297  }
4298  assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4299 
4300  /* maybe ests[j] is in-between two timepoints */
4301  if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4302  {
4303  assert(t > 0);
4304  coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4305  }
4306  else
4307  coreEnergyAfterEst[v] = energy;
4308  }
4309 
4310  t = ntimepoints - 1;
4311  energy = 0;
4312 
4313  /* compute core energy after the latest completion time of each job */
4314  for( v = nvars-1; v >= 0; --v )
4315  {
4316  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4317  {
4318  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4319  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4320  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4321  t--;
4322  }
4323  assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4324 
4325  /* maybe lcts[j] is in-between two timepoints */
4326  if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4327  {
4328  assert(t > 0);
4329  coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4330  }
4331  else
4332  coreEnergyAfterLct[v] = energy;
4333  }
4334 }
4335 
4336 /** collect earliest start times, latest completion time, and free energy contributions */
4337 static
4338 void collectDataTTEF(
4339  SCIP* scip, /**< SCIP data structure */
4340  int nvars, /**< number of start time variables (activities) */
4341  SCIP_VAR** vars, /**< array of start time variables */
4342  int* durations, /**< array of durations */
4343  int* demands, /**< array of demands */
4344  int hmin, /**< left bound of time axis to be considered (including hmin) */
4345  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4346  int* permests, /**< array to store the variable positions */
4347  int* ests, /**< array to store earliest start times */
4348  int* permlcts, /**< array to store the variable positions */
4349  int* lcts, /**< array to store latest completion times */
4350  int* ects, /**< array to store earliest completion times of the flexible part of the job */
4351  int* lsts, /**< array to store latest start times of the flexible part of the job */
4352  int* flexenergies /**< array to store the flexible energies of each job */
4353  )
4354 {
4355  int v;
4356 
4357  for( v = 0; v < nvars; ++ v)
4358  {
4359  int duration;
4360  int leftadjust;
4361  int rightadjust;
4362  int core;
4363  int est;
4364  int lct;
4365  int ect;
4366  int lst;
4367 
4368  duration = durations[v];
4369  assert(duration > 0);
4370 
4371  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4372  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
4373  ect = est + duration;
4374  lct = lst + duration;
4375 
4376  ests[v] = est;
4377  lcts[v] = lct;
4378  permests[v] = v;
4379  permlcts[v] = v;
4380 
4381  /* compute core time window which lies within the effective horizon */
4382  core = (int) computeCoreWithInterval(hmin, hmax, ect, lst);
4383 
4384  /* compute the number of time steps the job could run before the effective horizon */
4385  leftadjust = MAX(0, hmin - est);
4386 
4387  /* compute the number of time steps the job could run after the effective horizon */
4388  rightadjust = MAX(0, lct - hmax);
4389 
4390  /* compute for each job the energy which is flexible; meaning not part of the core */
4391  flexenergies[v] = duration - leftadjust - rightadjust - core;
4392  flexenergies[v] = MAX(0, flexenergies[v]);
4393  flexenergies[v] *= demands[v];
4394  assert(flexenergies[v] >= 0);
4395 
4396  /* the earliest completion time of the flexible energy */
4397  ects[v] = MIN(ect, lst);
4398 
4399  /* the latest start time of the flexible energy */
4400  lsts[v] = MAX(ect, lst);
4401  }
4402 }
4403 
4404 /** try to tighten the lower bound of the given variable */
4405 static
4407  SCIP* scip, /**< SCIP data structure */
4408  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4409  int nvars, /**< number of start time variables (activities) */
4410  SCIP_VAR** vars, /**< array of start time variables */
4411  int* durations, /**< array of durations */
4412  int* demands, /**< array of demands */
4413  int capacity, /**< cumulative capacity */
4414  int hmin, /**< left bound of time axis to be considered (including hmin) */
4415  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4416  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4417  int duration, /**< duration of the job */
4418  int demand, /**< demand of the job */
4419  int est, /**< earliest start time of the job */
4420  int ect, /**< earliest completion time of the flexible part of the job */
4421  int lct, /**< latest completion time of the job */
4422  int begin, /**< begin of the time window under investigation */
4423  int end, /**< end of the time window under investigation */
4424  SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4425  int* bestlb, /**< pointer to strope the best lower bound change */
4426  int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4427  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4428  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4429  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4430  )
4431 {
4432  int newlb;
4433 
4434  assert(begin >= hmin);
4435  assert(end <= hmax);
4436 
4437  /* check if the time-table edge-finding should infer bounds */
4438  if( !conshdlrdata->ttefinfer )
4439  return SCIP_OKAY;
4440 
4441  /* if the job can be processed completely before or after the time window, nothing can be tightened */
4442  if( est >= end || ect <= begin )
4443  return SCIP_OKAY;
4444 
4445  /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4446  * skip since the overload check will do the job
4447  */
4448  if( est >= begin && ect <= end )
4449  return SCIP_OKAY;
4450 
4451  /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4452  * earliest start time
4453  */
4454  if( energy >= demand * ((SCIP_Longint) MAX(begin, est) - MIN(end, ect)) )
4455  return SCIP_OKAY;
4456 
4457  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4458  * present; therefore, we need to add the core;
4459  *
4460  * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4461  * compute the earliest completion time of the (whole) job
4462  */
4463  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4464 
4465  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4466  *
4467  * @note we can round down the compute duration w.r.t. the available energy
4468  */
4469  newlb = end - (int) (energy / demand);
4470 
4471  /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4472  * bound (latest start time); meaning it is not possible to schedule the job
4473  */
4474  if( newlb > lct - duration )
4475  {
4476  /* initialize conflict analysis if conflict analysis is applicable */
4478  {
4479  SCIP_Real relaxedbd;
4480 
4481  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4482 
4483  /* it is enough to overshoot the upper bound of the variable by one */
4484  relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4485 
4486  /* initialize conflict analysis */
4488 
4489  /* added to upper bound (which was overcut be new lower bound) of the variable */
4490  SCIP_CALL( SCIPaddConflictUb(scip, var, NULL) );
4491 
4492  /* analyze the infeasible */
4493  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4494  begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4495 
4496  (*initialized) = TRUE;
4497  }
4498 
4499  (*cutoff) = TRUE;
4500  }
4501  else if( newlb > (*bestlb) )
4502  {
4503  INFERINFO inferinfo;
4504 
4505  assert(newlb > begin);
4506 
4507  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4508 
4509  /* construct inference information */
4510  (*inferinfos) = inferInfoToInt(inferinfo);
4511  (*bestlb) = newlb;
4512  }
4513 
4514  return SCIP_OKAY;
4515 }
4516 
4517 /** try to tighten the upper bound of the given variable */
4518 static
4520  SCIP* scip, /**< SCIP data structure */
4521  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4522  int nvars, /**< number of start time variables (activities) */
4523  SCIP_VAR** vars, /**< array of start time variables */
4524  int* durations, /**< array of durations */
4525  int* demands, /**< array of demands */
4526  int capacity, /**< cumulative capacity */
4527  int hmin, /**< left bound of time axis to be considered (including hmin) */
4528  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4529  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4530  int duration, /**< duration of the job */
4531  int demand, /**< demand of the job */
4532  int est, /**< earliest start time of the job */
4533  int lst, /**< latest start time of the flexible part of the job */
4534  int lct, /**< latest completion time of the job */
4535  int begin, /**< begin of the time window under investigation */
4536  int end, /**< end of the time window under investigation */
4537  SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4538  int* bestub, /**< pointer to strope the best upper bound change */
4539  int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4540  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4541  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4542  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4543  )
4544 {
4545  int newub;
4546 
4547  assert(begin >= hmin);
4548  assert(end <= hmax);
4549  assert(est < begin);
4550 
4551  /* check if the time-table edge-finding should infer bounds */
4552  if( !conshdlrdata->ttefinfer )
4553  return SCIP_OKAY;
4554 
4555  /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4556  if( lst >= end || lct <= begin )
4557  return SCIP_OKAY;
4558 
4559  /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4560  * skip since the overload check will do the job
4561  */
4562  if( lst >= begin && lct <= end )
4563  return SCIP_OKAY;
4564 
4565  /* check if the available energy in the time window is to small to handle the flexible part of the job */
4566  if( energy >= demand * ((SCIP_Longint) MIN(end, lct) - MAX(begin, lst)) )
4567  return SCIP_OKAY;
4568 
4569  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4570  * present; therefore, we need to add the core;
4571  *
4572  * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4573  * latest start of the (whole) job
4574  */
4575  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4576  assert(energy >= 0);
4577 
4578  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4579  *
4580  * @note we can round down the compute duration w.r.t. the available energy
4581  */
4582  assert(demand > 0);
4583  newub = begin - duration + (int) (energy / demand);
4584 
4585  /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4586  * bound (earliest start time); meaning it is not possible to schedule the job
4587  */
4588  if( newub < est )
4589  {
4590  /* initialize conflict analysis if conflict analysis is applicable */
4592  {
4593  SCIP_Real relaxedbd;
4594 
4595  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4596 
4597  /* it is enough to undershoot the lower bound of the variable by one */
4598  relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4599 
4600  /* initialize conflict analysis */
4602 
4603  /* added to lower bound (which was undercut be new upper bound) of the variable */
4604  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
4605 
4606  /* analyze the infeasible */
4607  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4608  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4609 
4610  (*initialized) = TRUE;
4611  }
4612 
4613  (*cutoff) = TRUE;
4614  }
4615  else if( newub < (*bestub) )
4616  {
4617  INFERINFO inferinfo;
4618 
4619  assert(newub < begin);
4620 
4621  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4622 
4623  /* construct inference information */
4624  (*inferinfos) = inferInfoToInt(inferinfo);
4625  (*bestub) = newub;
4626  }
4627 
4628  return SCIP_OKAY;
4629 }
4630 
4631 /** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4632 static
4634  SCIP* scip, /**< SCIP data structure */
4635  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4636  int nvars, /**< number of start time variables (activities) */
4637  SCIP_VAR** vars, /**< array of start time variables */
4638  int* durations, /**< array of durations */
4639  int* demands, /**< array of demands */
4640  int capacity, /**< cumulative capacity */
4641  int hmin, /**< left bound of time axis to be considered (including hmin) */
4642  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4643  int* newlbs, /**< array to buffer new lower bounds */
4644  int* newubs, /**< array to buffer new upper bounds */
4645  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4646  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4647  int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4648  int* flexenergies, /**< array of flexible energies in the same order as the variables */
4649  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4650  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4651  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4652  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4653  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4654  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4655  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4656  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4657  )
4658 {
4659  int coreEnergyAfterEnd;
4660  SCIP_Longint maxavailable;
4661  SCIP_Longint minavailable;
4662  SCIP_Longint totalenergy;
4663  int nests;
4664  int est;
4665  int lct;
4666  int start;
4667  int end;
4668  int v;
4669 
4670  est = INT_MAX;
4671  lct = INT_MIN;
4672 
4673  /* compute earliest start and latest completion time of all jobs */
4674  for( v = 0; v < nvars; ++v )
4675  {
4676  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4677  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4678 
4679  est = MIN(est, start);
4680  lct = MAX(lct, end);
4681  }
4682 
4683  /* adjust the effective time horizon */
4684  hmin = MAX(hmin, est);
4685  hmax = MIN(hmax, lct);
4686 
4687  end = hmax + 1;
4688  coreEnergyAfterEnd = -1;
4689 
4690  maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
4691  minavailable = maxavailable;
4692  totalenergy = computeTotalEnergy(durations, demands, nvars);
4693 
4694  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4695  if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4696  return SCIP_OKAY;
4697 
4698  nests = nvars;
4699 
4700  /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4701  * times define the end of the time interval under investigation
4702  */
4703  for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4704  {
4705  int flexenergy;
4706  int minbegin;
4707  int lbenergy;
4708  int lbcand;
4709  int i;
4710 
4711  lct = lcts[v];
4712 
4713  /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4714  * infinity capacity is available; hence we skip that
4715  */
4716  if( lct > hmax )
4717  continue;
4718 
4719  /* if the latest completion time is smaller then hmin we have to stop */
4720  if( lct <= hmin )
4721  {
4722  assert(v == 0 || lcts[v-1] <= lcts[v]);
4723  break;
4724  }
4725 
4726  /* if the latest completion time equals to previous end time, we can continue since this particular interval
4727  * induced by end was just analyzed
4728  */
4729  if( lct == end )
4730  continue;
4731 
4732  assert(lct < end);
4733 
4734  /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4735  * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4736  * free energy; if so it means that in the next iterate the free-energy cannot be negative
4737  */
4738  if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4739  {
4740  SCIP_Longint freeenergy;
4741 
4742  assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4743  assert(coreEnergyAfterEnd >= 0);
4744 
4745  /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4746  freeenergy = capacity * ((SCIP_Longint) end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4747 
4748  if( freeenergy <= minavailable )
4749  {
4750  SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%d>, free energy <%d>)\n", lct, minavailable, freeenergy);
4751  continue;
4752  }
4753  }
4754 
4755  SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4756 
4757  end = lct;
4758  coreEnergyAfterEnd = coreEnergyAfterLct[v];
4759 
4760  flexenergy = 0;
4761  minavailable = maxavailable;
4762  minbegin = hmax;
4763  lbcand = -1;
4764  lbenergy = 0;
4765 
4766  /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4767  * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4768  * wider
4769  */
4770  for( i = nests-1; i >= 0; --i )
4771  {
4772  SCIP_VAR* var;
4773  SCIP_Longint freeenergy;
4774  int duration;
4775  int demand;
4776  int begin;
4777  int idx;
4778  int lst;
4779 
4780  idx = perm[i];
4781  assert(idx >= 0);
4782  assert(idx < nvars);
4783  assert(!(*cutoff));
4784 
4785  /* the earliest start time of the job */
4786  est = ests[i];
4787 
4788  /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4789  * latest completion times (which define end) are scant in non-increasing order
4790  */
4791  if( end <= est )
4792  {
4793  nests--;
4794  continue;
4795  }
4796 
4797  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4798  * current ending time
4799  */
4800  if( ((SCIP_Longint) end - est) * capacity >= totalenergy )
4801  break;
4802 
4803  var = vars[idx];
4804  assert(var != NULL);
4805 
4806  duration = durations[idx];
4807  assert(duration > 0);
4808 
4809  demand = demands[idx];
4810  assert(demand > 0);
4811 
4812  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4813 
4814  /* the latest start time of the free part of the job */
4815  lst = lsts[idx];
4816 
4817  /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4818  * investigation; hence the overload check will do the the job
4819  */
4820  assert(est <= minbegin);
4821  if( minavailable < maxavailable && est < minbegin )
4822  {
4823  assert(!(*cutoff));
4824 
4825  /* try to tighten the upper bound */
4826  SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4827  var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4828  initialized, explanation, cutoff) );
4829 
4830  if( *cutoff )
4831  break;
4832  }
4833 
4834  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4835  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4836 
4837  begin = est;
4838  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4839 
4840  /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4841  * free energy
4842  */
4843  if( begin < hmin )
4844  break;
4845 
4846  /* compute the contribution to the flexible energy */
4847  if( lct <= end )
4848  {
4849  /* if the jobs has to finish before the end, all the energy has to be scheduled */
4850  assert(lst >= begin);
4851  assert(flexenergies[idx] >= 0);
4852  flexenergy += flexenergies[idx];
4853  }
4854  else
4855  {
4856  /* the job partly overlaps with the end */
4857  int candenergy;
4858  int energy;
4859 
4860  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4861  * w.r.t. latest start time
4862  *
4863  * @note we need to be aware of the effective horizon
4864  */
4865  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4866  assert(end - lst < duration);
4867  assert(energy >= 0);
4868 
4869  /* adjust the flexible energy of the time interval */
4870  flexenergy += energy;
4871 
4872  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4873  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4874  assert(candenergy >= 0);
4875 
4876  /* check if we found a better candidate */
4877  if( candenergy > lbenergy )
4878  {
4879  lbenergy = candenergy;
4880  lbcand = idx;
4881  }
4882  }
4883 
4884  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4885  assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4886 
4887  /* compute the energy which is not used yet */
4888  freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4889 
4890  /* check overload */
4891  if( freeenergy < 0 )
4892  {
4893  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4894 
4895  /* initialize conflict analysis if conflict analysis is applicable */
4897  {
4898  /* analyze infeasibilty */
4900 
4901  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4902  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
4903  conshdlrdata->usebdwidening, explanation) );
4904 
4905  (*initialized) = TRUE;
4906  }
4907 
4908  (*cutoff) = TRUE;
4909 
4910  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4911  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
4912 
4913  break;
4914  }
4915 
4916  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4917  if( lbenergy > 0 && freeenergy < lbenergy )
4918  {
4919  SCIP_Longint energy;
4920  int newlb;
4921  int ect;
4922 
4923  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4924  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4925 
4926  /* remove the energy of our job from the ... */
4927  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) end - lsts[lbcand])) * demands[lbcand];
4928 
4929  newlb = end - (int)(energy / demands[lbcand]);
4930 
4931  if( newlb > lst )
4932  {
4933  /* initialize conflict analysis if conflict analysis is applicable */
4935  {
4936  SCIP_Real relaxedbd;
4937 
4938  /* analyze infeasibilty */
4940 
4941  relaxedbd = lst + 1.0;
4942 
4943  /* added to upper bound (which was overcut be new lower bound) of the variable */
4944  SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4945 
4946  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4947  begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
4948  conshdlrdata->usebdwidening, explanation) );
4949 
4950  (*initialized) = TRUE;
4951  }
4952 
4953  (*cutoff) = TRUE;
4954  break;
4955  }
4956  else if( newlb > newlbs[lbcand] )
4957  {
4958  INFERINFO inferinfo;
4959 
4960  /* construct inference information */
4961  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4962 
4963  /* buffer upper bound change */
4964  lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
4965  newlbs[lbcand] = newlb;
4966  }
4967  }
4968 
4969  /* check if the current interval has a smaller free energy */
4970  if( minavailable > freeenergy )
4971  {
4972  minavailable = freeenergy;
4973  minbegin = begin;
4974  }
4975  assert(minavailable >= 0);
4976  }
4977  }
4978 
4979  return SCIP_OKAY;
4980 }
4981 
4982 /** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
4983 static
4985  SCIP* scip, /**< SCIP data structure */
4986  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4987  int nvars, /**< number of start time variables (activities) */
4988  SCIP_VAR** vars, /**< array of start time variables */
4989  int* durations, /**< array of durations */
4990  int* demands, /**< array of demands */
4991  int capacity, /**< cumulative capacity */
4992  int hmin, /**< left bound of time axis to be considered (including hmin) */
4993  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4994  int* newlbs, /**< array to buffer new lower bounds */
4995  int* newubs, /**< array to buffer new upper bounds */
4996  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4997  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4998  int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
4999  int* flexenergies, /**< array of flexible energies in the same order as the variables */
5000  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
5001  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
5002  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
5003  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
5004  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
5005  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5006  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5007  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5008  )
5009 {
5010  int coreEnergyAfterStart;
5011  SCIP_Longint maxavailable;
5012  SCIP_Longint minavailable;
5013  SCIP_Longint totalenergy;
5014  int nlcts;
5015  int begin;
5016  int minest;
5017  int maxlct;
5018  int start;
5019  int end;
5020  int v;
5021 
5022  if( *cutoff )
5023  return SCIP_OKAY;
5024 
5025  begin = hmin - 1;
5026 
5027  minest = INT_MAX;
5028  maxlct = INT_MIN;
5029 
5030  /* compute earliest start and latest completion time of all jobs */
5031  for( v = 0; v < nvars; ++v )
5032  {
5033  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5034  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
5035 
5036  minest = MIN(minest, start);
5037  maxlct = MAX(maxlct, end);
5038  }
5039 
5040  /* adjust the effective time horizon */
5041  hmin = MAX(hmin, minest);
5042  hmax = MIN(hmax, maxlct);
5043 
5044  maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
5045  totalenergy = computeTotalEnergy(durations, demands, nvars);
5046 
5047  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5048  if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5049  return SCIP_OKAY;
5050 
5051  nlcts = 0;
5052 
5053  /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5054  * define the start of the time interval under investigation
5055  */
5056  for( v = 0; v < nvars; ++v )
5057  {
5058  int flexenergy;
5059  int minend;
5060  int ubenergy;
5061  int ubcand;
5062  int est;
5063  int i;
5064 
5065  est = ests[v];
5066 
5067  /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5068  * infinity capacity is available; hence we skip that
5069  */
5070  if( est < hmin )
5071  continue;
5072 
5073  /* if the earliest start time is larger or equal then hmax we have to stop */
5074  if( est >= hmax )
5075  break;
5076 
5077  /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5078  * induced by start was just analyzed
5079  */
5080  if( est == begin )
5081  continue;
5082 
5083  assert(est > begin);
5084 
5085  SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5086 
5087  begin = est;
5088  coreEnergyAfterStart = coreEnergyAfterEst[v];
5089 
5090  flexenergy = 0;
5091  minavailable = maxavailable;
5092  minend = hmin;
5093  ubcand = -1;
5094  ubenergy = 0;
5095 
5096  /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5097  * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5098  */
5099  for( i = nlcts; i < nvars; ++i )
5100  {
5101  SCIP_VAR* var;
5102  SCIP_Longint freeenergy;
5103  int duration;
5104  int demand;
5105  int idx;
5106  int lct;
5107  int ect;
5108 
5109  idx = perm[i];
5110  assert(idx >= 0);
5111  assert(idx < nvars);
5112  assert(!(*cutoff));
5113 
5114  /* the earliest start time of the job */
5115  lct = lcts[i];
5116 
5117  /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5118  * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5119  */
5120  if( lct <= begin )
5121  {
5122  nlcts++;
5123  continue;
5124  }
5125 
5126  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5127  * start with current beginning time
5128  */
5129  if( ((SCIP_Longint) lct - begin) * capacity >= totalenergy )
5130  break;
5131 
5132  var = vars[idx];
5133  assert(var != NULL);
5134 
5135  duration = durations[idx];
5136  assert(duration > 0);
5137 
5138  demand = demands[idx];
5139  assert(demand > 0);
5140 
5141  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5142 
5143  /* the earliest completion time of the flexible part of the job */
5144  ect = ects[idx];
5145 
5146  /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5147  * investigation; hence the overload check will do the the job
5148  */
5149  assert(lct >= minend);
5150  if( minavailable < maxavailable && lct > minend )
5151  {
5152  assert(!(*cutoff));
5153 
5154  /* try to tighten the upper bound */
5155  SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5156  var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5157  initialized, explanation, cutoff) );
5158 
5159  if( *cutoff )
5160  return SCIP_OKAY;
5161  }
5162 
5163  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5164  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5165 
5166  end = lct;
5167  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5168 
5169  /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5170  * free energy
5171  */
5172  if( end > hmax )
5173  break;
5174 
5175  /* compute the contribution to the flexible energy */
5176  if( est >= begin )
5177  {
5178  /* if the jobs has to finish before the end, all the energy has to be scheduled */
5179  assert(ect <= end);
5180  assert(flexenergies[idx] >= 0);
5181  flexenergy += flexenergies[idx];
5182  }
5183  else
5184  {
5185  /* the job partly overlaps with the end */
5186  int candenergy;
5187  int energy;
5188 
5189  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5190  * w.r.t. latest start time
5191  *
5192  * @note we need to be aware of the effective horizon
5193  */
5194  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5195  assert(ect - begin < duration);
5196  assert(energy >= 0);
5197 
5198  /* adjust the flexible energy of the time interval */
5199  flexenergy += energy;
5200 
5201  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5202  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5203  assert(candenergy >= 0);
5204 
5205  /* check if we found a better candidate */
5206  if( candenergy > ubenergy )
5207  {
5208  ubenergy = candenergy;
5209  ubcand = idx;
5210  }
5211  }
5212 
5213  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5214  assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5215 
5216  /* compute the energy which is not used yet */
5217  freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5218 
5219  /* check overload */
5220  if( freeenergy < 0 )
5221  {
5222  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5223 
5224  /* initialize conflict analysis if conflict analysis is applicable */
5226  {
5227  /* analyze infeasibilty */
5229 
5230  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5231  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
5232  conshdlrdata->usebdwidening, explanation) );
5233 
5234  (*initialized) = TRUE;
5235  }
5236 
5237  (*cutoff) = TRUE;
5238 
5239  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5240  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5241 
5242  return SCIP_OKAY;
5243  }
5244 
5245  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5246  if( ubenergy > 0 && freeenergy < ubenergy )
5247  {
5248  SCIP_Longint energy;
5249  int newub;
5250  int lst;
5251 
5252  duration = durations[ubcand];
5253  assert(duration > 0);
5254 
5255  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5256  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5257 
5258  /* remove the energy of our job from the ... */
5259  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) ects[ubcand] - begin)) * demands[ubcand];
5260 
5261  newub = begin - duration + (int)(energy / demands[ubcand]);
5262 
5263  if( newub < ect - duration )
5264  {
5265  /* initialize conflict analysis if conflict analysis is applicable */
5267  {
5268  SCIP_Real relaxedbd;
5269  /* analyze infeasibilty */
5271 
5272  relaxedbd = ect - duration - 1.0;
5273 
5274  /* added to lower bound (which was undercut be new upper bound) of the variable */
5275  SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5276 
5277  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5278  begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5279  conshdlrdata->usebdwidening, explanation) );
5280 
5281  (*initialized) = TRUE;
5282  }
5283 
5284  (*cutoff) = TRUE;
5285  return SCIP_OKAY;
5286  }
5287  else if( newub < newubs[ubcand] )
5288  {
5289  INFERINFO inferinfo;
5290 
5291  /* construct inference information */
5292  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5293 
5294  /* buffer upper bound change */
5295  ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5296  newubs[ubcand] = newub;
5297  }
5298  }
5299 
5300  /* check if the current interval has a smaller free energy */
5301  if( minavailable > freeenergy )
5302  {
5303  minavailable = freeenergy;
5304  minend = end;
5305  }
5306  assert(minavailable >= 0);
5307  }
5308  }
5309 
5310  return SCIP_OKAY;
5311 }
5312 
5313 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5314  * edge-finding
5315  *
5316  * @note The algorithm is based on the following two papers:
5317  * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5318  * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5319  * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5320  * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5321  * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5322  */
5323 static
5325  SCIP* scip, /**< SCIP data structure */
5326  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5327  SCIP_PROFILE* profile, /**< current core profile */
5328  int nvars, /**< number of start time variables (activities) */
5329  SCIP_VAR** vars, /**< array of start time variables */
5330  int* durations, /**< array of durations */
5331  int* demands, /**< array of demands */
5332  int capacity, /**< cumulative capacity */
5333  int hmin, /**< left bound of time axis to be considered (including hmin) */
5334  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5335  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5336  int* nchgbds, /**< pointer to store the number of bound changes */
5337  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5338  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5339  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5340  )
5341 {
5342  int* coreEnergyAfterEst;
5343  int* coreEnergyAfterLct;
5344  int* flexenergies;
5345  int* permests;
5346  int* permlcts;
5347  int* lcts;
5348  int* ests;
5349  int* ects;
5350  int* lsts;
5351 
5352  int* newlbs;
5353  int* newubs;
5354  int* lbinferinfos;
5355  int* ubinferinfos;
5356 
5357  int v;
5358 
5359  /* check if a cutoff was already detected */
5360  if( (*cutoff) )
5361  return SCIP_OKAY;
5362 
5363  /* check if at least the basic overload checking should be perfomed */
5364  if( !conshdlrdata->ttefcheck )
5365  return SCIP_OKAY;
5366 
5367  SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5368 
5369  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5370  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5371  SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5372  SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5373  SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5374  SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5375  SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5376  SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5377  SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5378 
5379  SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5380  SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5381  SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5382  SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5383 
5384  /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5385  for( v = 0; v < nvars; ++v )
5386  {
5387  newlbs[v] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5388  newubs[v] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5389  lbinferinfos[v] = 0;
5390  ubinferinfos[v] = 0;
5391  }
5392 
5393  /* collect earliest start times, latest completion time, and free energy contributions */
5394  collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5395 
5396  /* sort the earliest start times and latest completion in non-decreasing order */
5397  SCIPsortIntInt(ests, permests, nvars);
5398  SCIPsortIntInt(lcts, permlcts, nvars);
5399 
5400  /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5401  * points
5402  */
5403  computeCoreEnergyAfter(profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct);
5404 
5405  /* propagate the upper bounds and "opportunistically" the lower bounds */
5406  SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5407  newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5408  permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5409 
5410  /* propagate the lower bounds and "opportunistically" the upper bounds */
5411  SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5412  newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5413  permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5414 
5415  /* apply the buffer bound changes */
5416  for( v = 0; v < nvars && !(*cutoff); ++v )
5417  {
5418  SCIP_Bool infeasible;
5419  SCIP_Bool tightened;
5420 
5421  SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v], TRUE, &infeasible, &tightened) );
5422 
5423  /* since we change first the lower bound of the variable an infeasibilty should be detected */
5424  assert(!infeasible);
5425 
5426  if( tightened )
5427  {
5428  (*nchgbds)++;
5429 
5430  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5432  }
5433 
5434  SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v], TRUE, &infeasible, &tightened) );
5435 
5436  /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5437  * bound update can be infeasible
5438  */
5439  if( infeasible )
5440  {
5442  {
5443  INFERINFO inferinfo;
5444  SCIP_VAR* var;
5445  int begin;
5446  int end;
5447 
5448  var = vars[v];
5449  assert(var != NULL);
5450 
5451  /* initialize conflict analysis */
5453 
5454  /* convert int to inference information */
5455  inferinfo = intToInferInfo(ubinferinfos[v]);
5456 
5457  /* collect time window from inference information */
5458  begin = inferInfoGetData1(inferinfo);
5459  end = inferInfoGetData2(inferinfo);
5460  assert(begin < end);
5461 
5462  /* added to lower bound (which was undercut be new upper bound) of the variable */
5463  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
5464 
5465  /* analysis the upper bound change */
5466  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5467  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5468  conshdlrdata->usebdwidening, explanation) );
5469 
5470  (*initialized) = TRUE;
5471  }
5472 
5473  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5474  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5475 
5476  (*cutoff) = TRUE;
5477  break;
5478  }
5479 
5480  if( tightened )
5481  {
5482  (*nchgbds)++;
5483 
5484  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5486  }
5487  }
5488 
5489  SCIPfreeBufferArray(scip, &ubinferinfos);
5490  SCIPfreeBufferArray(scip, &lbinferinfos);
5491  SCIPfreeBufferArray(scip, &newubs);
5492  SCIPfreeBufferArray(scip, &newlbs);
5493 
5494  /* free buffer arrays */
5495  SCIPfreeBufferArray(scip, &lsts);
5496  SCIPfreeBufferArray(scip, &ects);
5497  SCIPfreeBufferArray(scip, &ests);
5498  SCIPfreeBufferArray(scip, &lcts);
5499  SCIPfreeBufferArray(scip, &permests);
5500  SCIPfreeBufferArray(scip, &permlcts);
5501  SCIPfreeBufferArray(scip, &flexenergies);
5502  SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5503  SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5504 
5505  return SCIP_OKAY;
5506 }
5507 
5508 /** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5509  * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5510  * time table propagator
5511  */
5512 static
5514  SCIP* scip, /**< SCIP data structure */
5515  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5516  SCIP_PROFILE* profile, /**< core profile */
5517  int nvars, /**< number of start time variables (activities) */
5518  SCIP_VAR** vars, /**< array of start time variables */
5519  int* durations, /**< array of durations */
5520  int* demands, /**< array of demands */
5521  int capacity, /**< cumulative capacity */
5522  int hmin, /**< left bound of time axis to be considered (including hmin) */
5523  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5524  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5525  int* nchgbds, /**< pointer to store the number of bound changes */
5526  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5527  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5528  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5529  )
5530 {
5531  SCIP_Bool infeasible;
5532  int v;
5533 
5534  assert(scip != NULL);
5535  assert(nvars > 0);
5536  assert(cons != NULL);
5537  assert(cutoff != NULL);
5538 
5539  /* check if already a cutoff was detected */
5540  if( (*cutoff) )
5541  return SCIP_OKAY;
5542 
5543  /* check if the time tabling should infer bounds */
5544  if( !conshdlrdata->ttinfer )
5545  return SCIP_OKAY;
5546 
5547  assert(*initialized == FALSE);
5548 
5549  SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5550  SCIPconsGetName(cons), hmin, hmax, capacity);
5551 
5552  infeasible = FALSE;
5553 
5554  /* if core profile is empty; nothing to do */
5555  if( SCIPprofileGetNTimepoints(profile) <= 1 )
5556  return SCIP_OKAY;
5557 
5558  /* start checking each job whether the bounds can be improved */
5559  for( v = 0; v < nvars; ++v )
5560  {
5561  SCIP_VAR* var;
5562  int demand;
5563  int duration;
5564  int begin;
5565  int end;
5566  int est;
5567  int lst;
5568 
5569  var = vars[v];
5570  assert(var != NULL);
5571 
5572  duration = durations[v];
5573  assert(duration > 0);
5574 
5575  /* collect earliest and latest start time */
5576  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5577  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5578 
5579  /* check if the start time variables is already fixed; in that case we can ignore the job */
5580  if( est == lst )
5581  continue;
5582 
5583  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5584  if( lst + duration <= hmin || est >= hmax )
5585  continue;
5586 
5587  /* compute core interval w.r.t. effective time horizon */
5588  begin = MAX(hmin, lst);
5589  end = MIN(hmax, est + duration);
5590 
5591  demand = demands[v];
5592  assert(demand > 0);
5593 
5594  /* if the job has a core, remove it first */
5595  if( begin < end )
5596  {
5597  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5598  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5599 
5600  SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5601  }
5602 
5603  /* first try to update the earliest start time */
5604  SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5605  profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5606 
5607  if( *cutoff )
5608  break;
5609 
5610  /* second try to update the latest start time */
5611  SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5612  profile, v, nchgbds) );
5613 
5614  if( *cutoff )
5615  break;
5616 
5617  /* collect the potentially updated earliest and latest start time */
5618  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5619  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5620 
5621  /* compute core interval w.r.t. effective time horizon */
5622  begin = MAX(hmin, lst);
5623  end = MIN(hmax, est + duration);
5624 
5625  /* after updating the bound we might have a new core */
5626  if( begin < end )
5627  {
5628  int pos;
5629 
5630  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5631  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5632 
5633  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5634 
5635  if( infeasible )
5636  {
5637  /* use conflict analysis to analysis the core insertion which was infeasible */
5638  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5639  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5640 
5641  if( explanation != NULL )
5642  explanation[v] = TRUE;
5643 
5644  (*cutoff) = TRUE;
5645 
5646  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5647  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
5648 
5649  break;
5650  }
5651  }
5652  }
5653 
5654  return SCIP_OKAY;
5655 }
5656 
5657 
5658 /** node data structure for the binary tree used for edgefinding (with overload checking) */
5659 struct SCIP_NodeData
5660 {
5661  SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5662  SCIP_Real key; /**< key which is to insert the corresponding search node */
5663  int est; /**< earliest start time if the node data belongs to a leaf */
5664  int lct; /**< latest completion time if the node data belongs to a leaf */
5665  int demand; /**< demand of the job if the node data belongs to a leaf */
5666  int duration; /**< duration of the job if the node data belongs to a leaf */
5667  int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5668  int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5669  SCIP_Longint enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5670  int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5671  int energylambda;
5672  SCIP_Longint enveloplambda;
5673  int idx; /**< index of the start time variable in the (global) variable array */
5674  SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5675 };
5676 typedef struct SCIP_NodeData SCIP_NODEDATA;
5678 /** creates a node data structure */
5679 static
5681  SCIP* scip, /**< SCIP data structure */
5682  SCIP_NODEDATA** nodedata /**< pointer to store the create node data */
5683  )
5684 {
5685  SCIP_CALL( SCIPallocBuffer(scip, nodedata) );
5686  (*nodedata)->var = NULL;
5687  (*nodedata)->key = SCIP_INVALID;
5688  (*nodedata)->est = INT_MIN;
5689  (*nodedata)->lct = INT_MAX;
5690  (*nodedata)->duration = 0;
5691  (*nodedata)->demand = 0;
5692  (*nodedata)->enveloptheta = -1;
5693  (*nodedata)->energytheta = 0;
5694  (*nodedata)->enveloplambda = -1;
5695  (*nodedata)->energylambda = -1;
5696  (*nodedata)->idx = -1;
5697  (*nodedata)->intheta = TRUE;
5698 
5699  return SCIP_OKAY;
5700 }
5701 
5702 /** frees a node data structure */
5703 static
5704 void freeNodedata(
5705  SCIP* scip, /**< SCIP data structure */
5706  SCIP_NODEDATA** nodedata /**< pointer to store node data which should be freed */
5707  )
5708 {
5709  if( *nodedata != NULL )
5710  {
5711  SCIPfreeBuffer(scip, nodedata);
5712  }
5713 }
5714 
5715 /** update node data structure starting from the given node along the path to the root node */
5716 static
5717 void updateEnvelope(
5718  SCIP* scip, /**< SCIP data structure */
5719  SCIP_BTNODE* node /**< search node which inserted */
5720  )
5721 {
5722  SCIP_BTNODE* left;
5723  SCIP_BTNODE* right;
5724  SCIP_NODEDATA* nodedata;
5725  SCIP_NODEDATA* leftdata;
5726  SCIP_NODEDATA* rightdata;
5727 
5728  SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5729 
5730  if( SCIPbtnodeIsLeaf(node) )
5731  node = SCIPbtnodeGetParent(node);
5732 
5733  while( node != NULL )
5734  {
5735  /* get node data */
5736  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5737  assert(nodedata != NULL);
5738 
5739  /* collect node data from left node */
5740  left = SCIPbtnodeGetLeftchild(node);
5741  assert(left != NULL);
5742  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5743  assert(leftdata != NULL);
5744 
5745  /* collect node data from right node */
5746  right = SCIPbtnodeGetRightchild(node);
5747  assert(right != NULL);
5748  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5749  assert(rightdata != NULL);
5750 
5751  /* update envelop and energy */
5752  if( leftdata->enveloptheta >= 0 )
5753  {
5754  assert(rightdata->energytheta != -1);
5755  nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5756  }
5757  else
5758  nodedata->enveloptheta = rightdata->enveloptheta;
5759 
5760  assert(leftdata->energytheta != -1);
5761  assert(rightdata->energytheta != -1);
5762  nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5763 
5764  if( leftdata->enveloplambda >= 0 )
5765  {
5766  assert(rightdata->energytheta != -1);
5767  nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5768  }
5769  else
5770  nodedata->enveloplambda = rightdata->enveloplambda;
5771 
5772  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5773  nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5774 
5775  SCIPdebugMsg(scip, "node <%p> lambda envelop %d\n", (void*)node, nodedata->enveloplambda);
5776 
5777  if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5778  {
5779  assert(rightdata->energytheta != -1);
5780  assert(leftdata->energytheta != -1);
5781  nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5782  }
5783  else if( rightdata->energylambda >= 0 )
5784  {
5785  assert(leftdata->energytheta != -1);
5786  nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5787  }
5788  else if( leftdata->energylambda >= 0 )
5789  {
5790  assert(rightdata->energytheta != -1);
5791  nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5792  }
5793  else
5794  nodedata->energylambda = -1;
5795 
5796  /* go to parent */
5797  node = SCIPbtnodeGetParent(node);
5798  }
5799 
5800  SCIPdebugMsg(scip, "updating done\n");
5801 }
5802 
5803 /** updates the key of the first parent on the trace which comes from left */
5804 static
5805 void updateKeyOnTrace(
5806  SCIP_BTNODE* node, /**< node to start the trace */
5807  SCIP_Real key /**< update search key */
5808  )
5809 {
5810  assert(node != NULL);
5811 
5812  while( !SCIPbtnodeIsRoot(node) )
5813  {
5814  SCIP_BTNODE* parent;
5815 
5816  parent = SCIPbtnodeGetParent(node);
5817  assert(parent != NULL);
5818 
5819  if( SCIPbtnodeIsLeftchild(node) )
5820  {
5821  SCIP_NODEDATA* nodedata;
5822 
5823  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(parent);
5824  assert(nodedata != NULL);
5825 
5826  nodedata->key = key;
5827  return;
5828  }
5829 
5830  node = parent;
5831  }
5832 }
5833 
5834 
5835 /** deletes the given node and updates all envelops */
5836 static
5838  SCIP* scip, /**< SCIP data structure */
5839  SCIP_BT* tree, /**< binary tree */
5840  SCIP_BTNODE* node /**< node to be deleted */
5841  )
5842 {
5843  SCIP_BTNODE* parent;
5844  SCIP_BTNODE* grandparent;
5845  SCIP_BTNODE* sibling;
5846 
5847  assert(scip != NULL);
5848  assert(tree != NULL);
5849  assert(node != NULL);
5850 
5851  assert(SCIPbtnodeIsLeaf(node));
5852  assert(!SCIPbtnodeIsRoot(node));
5853 
5854  SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5855 
5856  parent = SCIPbtnodeGetParent(node);
5857  assert(parent != NULL);
5858  if( SCIPbtnodeIsLeftchild(node) )
5859  {
5860  sibling = SCIPbtnodeGetRightchild(parent);
5861  SCIPbtnodeSetRightchild(parent, NULL);
5862  }
5863  else
5864  {
5865  sibling = SCIPbtnodeGetLeftchild(parent);
5866  SCIPbtnodeSetLeftchild(parent, NULL);
5867  }
5868  assert(sibling != NULL);
5869 
5870  grandparent = SCIPbtnodeGetParent(parent);
5871 
5872  if( grandparent != NULL )
5873  {
5874  /* reset parent of sibling */
5875  SCIPbtnodeSetParent(sibling, grandparent);
5876 
5877  /* reset child of grandparent to sibling */
5878  if( SCIPbtnodeIsLeftchild(parent) )
5879  {
5880  SCIPbtnodeSetLeftchild(grandparent, sibling);
5881  }
5882  else
5883  {
5884  SCIP_NODEDATA* nodedata;
5885 
5886  assert(SCIPbtnodeIsRightchild(parent));
5887  SCIPbtnodeSetRightchild(grandparent, sibling);
5888 
5889  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(sibling);
5890 
5891  updateKeyOnTrace(grandparent, nodedata->key);
5892  }
5893 
5894  updateEnvelope(scip, grandparent);
5895  }
5896  else
5897  {
5898  SCIPbtnodeSetParent(sibling, NULL);
5899 
5900  SCIPbtSetRoot(tree, sibling);
5901  }
5902 
5903  SCIPbtnodeFree(tree, &parent);
5904 
5905  return SCIP_OKAY;
5906 }
5907 
5908 /** moves a node form the theta set into the lambda set and updates the envelops */
5909 static
5911  SCIP* scip, /**< SCIP data structure */
5912  SCIP_BT* tree, /**< binary tree */
5913  SCIP_BTNODE* node /**< node to move into the lambda set */
5914  )
5915 {
5916  SCIP_NODEDATA* nodedata;
5917 
5918  assert(scip != NULL);
5919  assert(tree != NULL);
5920  assert(node != NULL);
5921 
5922  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5923  assert(nodedata != NULL);
5924  assert(nodedata->intheta);
5925 
5926  /* move the contributions form the theta set into the lambda set */
5927  assert(nodedata->enveloptheta != -1);
5928  assert(nodedata->energytheta != -1);
5929  assert(nodedata->enveloplambda == -1);
5930  assert(nodedata->energylambda == -1);
5931  nodedata->enveloplambda = nodedata->enveloptheta;
5932  nodedata->energylambda = nodedata->energytheta;
5933 
5934  nodedata->enveloptheta = -1;
5935  nodedata->energytheta = 0;
5936  nodedata->intheta = FALSE;
5937 
5938  /* update the energy and envelop values on trace */
5939  updateEnvelope(scip, node);
5940 
5941  return SCIP_OKAY;
5942 }
5943 
5944 /** inserts a node into the theta set and update the envelops */
5945 static
5947  SCIP* scip, /**< SCIP data structure */
5948  SCIP_BT* tree, /**< binary tree */
5949  SCIP_BTNODE* node, /**< node to insert */
5950  SCIP_NODEDATA** nodedatas, /**< array of node data */
5951  int* nnodedatas /**< pointer to number of node data */
5952  )
5953 {
5954  /* if the tree is empty the node will be the root node */
5955  if( SCIPbtIsEmpty(tree) )
5956  {
5957  SCIPbtSetRoot(tree, node);
5958  }
5959  else
5960  {
5961  SCIP_NODEDATA* newnodedata;
5962  SCIP_NODEDATA* leafdata;
5963  SCIP_NODEDATA* nodedata;
5964  SCIP_BTNODE* leaf;
5965  SCIP_BTNODE* newnode;
5966  SCIP_BTNODE* parent;
5967 
5968  leaf = SCIPbtGetRoot(tree);
5969  assert(leaf != NULL);
5970 
5971  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5972  assert(leafdata != NULL);
5973 
5974  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5975  assert(nodedata != NULL);
5976  assert(nodedata->intheta);
5977 
5978  /* find the position to insert the node */
5979  while( !SCIPbtnodeIsLeaf(leaf) )
5980  {
5981  if( nodedata->key < leafdata->key )
5982  leaf = SCIPbtnodeGetLeftchild(leaf);
5983  else
5984  leaf = SCIPbtnodeGetRightchild(leaf);
5985 
5986  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5987  assert(leafdata != NULL);
5988  }
5989 
5990  assert(leaf != NULL);
5991  assert(leaf != node);
5992 
5993  /* create node data */
5994  SCIP_CALL( createNodedata(scip, &newnodedata) );
5995 
5996  /* create a new node */
5997  SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
5998  assert(newnode != NULL);
5999 
6000  /* store node data to be able to delete them latter */
6001  nodedatas[*nnodedatas] = newnodedata;
6002  (*nnodedatas)++;
6003 
6004  parent = SCIPbtnodeGetParent(leaf);
6005 
6006  if( parent != NULL )
6007  {
6008  SCIPbtnodeSetParent(newnode, parent);
6009 
6010  /* check if the node is the left child */
6011  if( SCIPbtnodeGetLeftchild(parent) == leaf )
6012  {
6013  SCIPbtnodeSetLeftchild(parent, newnode);
6014  }
6015  else
6016  {
6017  SCIPbtnodeSetRightchild(parent, newnode);
6018  }
6019  }
6020  else
6021  SCIPbtSetRoot(tree, newnode);
6022 
6023  if( nodedata->key < leafdata->key )
6024  {
6025  /* node is on the left */
6026  SCIPbtnodeSetLeftchild(newnode, node);
6027  SCIPbtnodeSetRightchild(newnode, leaf);
6028  newnodedata->key = nodedata->key;
6029  }
6030  else
6031  {
6032  /* leaf is on the left */
6033  SCIPbtnodeSetLeftchild(newnode, leaf);
6034  SCIPbtnodeSetRightchild(newnode, node);
6035  newnodedata->key = leafdata->key;
6036  }
6037 
6038  SCIPbtnodeSetParent(leaf, newnode);
6039  SCIPbtnodeSetParent(node, newnode);
6040  }
6041 
6042  /* update envelop */
6043  updateEnvelope(scip, node);
6044 
6045  return SCIP_OKAY;
6046 }
6047 
6048 /** returns the leaf responsible for the lambda energy */
6049 static
6051  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6052  )
6053 {
6054  SCIP_BTNODE* left;
6055  SCIP_BTNODE* right;
6056  SCIP_NODEDATA* nodedata;
6057  SCIP_NODEDATA* leftdata;
6058  SCIP_NODEDATA* rightdata;
6059 
6060  assert(node != NULL);
6061 
6062  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6063  assert(nodedata != NULL);
6064 
6065  /* check if the node is the (responsible) leaf */
6066  if( SCIPbtnodeIsLeaf(node) )
6067  {
6068  assert(!nodedata->intheta);
6069  return node;
6070  }
6071 
6072  left = SCIPbtnodeGetLeftchild(node);
6073  assert(left != NULL);
6074 
6075  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6076  assert(leftdata != NULL);
6077 
6078  right = SCIPbtnodeGetRightchild(node);
6079  assert(right != NULL);
6080 
6081  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6082  assert(rightdata != NULL);
6083 
6084  assert(nodedata->energylambda != -1);
6085  assert(rightdata->energytheta != -1);
6086 
6087  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6089 
6090  assert(leftdata->energytheta != -1);
6091  assert(rightdata->energylambda != -1);
6092  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6093 
6095 }
6096 
6097 /** returns the leaf responsible for the lambda envelop */
6098 static
6100  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6101  )
6102 {
6103  SCIP_BTNODE* left;
6104  SCIP_BTNODE* right;
6105  SCIP_NODEDATA* nodedata;
6106  SCIP_NODEDATA* leftdata;
6107  SCIP_NODEDATA* rightdata;
6108 
6109  assert(node != NULL);
6110 
6111  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6112  assert(nodedata != NULL);
6113 
6114  /* check if the node is the (responsible) leaf */
6115  if( SCIPbtnodeIsLeaf(node) )
6116  {
6117  assert(!nodedata->intheta);
6118  return node;
6119  }
6120 
6121  left = SCIPbtnodeGetLeftchild(node);
6122  assert(left != NULL);
6123 
6124  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6125  assert(leftdata != NULL);
6126 
6127  right = SCIPbtnodeGetRightchild(node);
6128  assert(right != NULL);
6129 
6130  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6131  assert(rightdata != NULL);
6132 
6133  assert(nodedata->enveloplambda != -1);
6134  assert(rightdata->energytheta != -1);
6135 
6136  /* check if the left or right child is the one defining the envelop for the lambda set */
6137  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6139  else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6140  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6142 
6143  assert(rightdata->enveloplambda != -1);
6144  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6145 
6147 }
6148 
6149 
6150 /** reports all elements from set theta to generate a conflicting set */
6151 static
6152 void collectThetaSubtree(
6153  SCIP_BTNODE* node, /**< node within a theta subtree */
6154  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6155  int* nelements, /**< pointer to store the number of elements in omegaset */
6156  int* est, /**< pointer to store the earliest start time of the omega set */
6157  int* lct, /**< pointer to store the latest start time of the omega set */
6158  int* energy /**< pointer to store the energy of the omega set */
6159  )
6160 {
6161  SCIP_NODEDATA* nodedata;
6162 
6163  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6164  assert(nodedata != NULL);
6165 
6166  if( !SCIPbtnodeIsLeaf(node) )
6167  {
6168  collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6169  collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6170  }
6171  else if( nodedata->intheta )
6172  {
6173  assert(nodedata->var != NULL);
6174  SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6175 
6176  omegaset[*nelements] = node;
6177  (*est) = MIN(*est, nodedata->est);
6178  (*lct) = MAX(*lct, nodedata->lct);
6179  (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6180  (*nelements)++;
6181  }
6182 }
6183 
6184 
6185 /** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6186 static
6187 void traceThetaEnvelop(
6188  SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6189  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6190  int* nelements, /**< pointer to store the number of elements in omegaset */
6191  int* est, /**< pointer to store the earliest start time of the omega set */
6192  int* lct, /**< pointer to store the latest start time of the omega set */
6193  int* energy /**< pointer to store the energy of the omega set */
6194  )
6195 {
6196  assert(node != NULL);
6197 
6198  if( SCIPbtnodeIsLeaf(node) )
6199  {
6200  collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6201  }
6202  else
6203  {
6204  SCIP_BTNODE* left;
6205  SCIP_BTNODE* right;
6206  SCIP_NODEDATA* nodedata;
6207  SCIP_NODEDATA* leftdata;
6208  SCIP_NODEDATA* rightdata;
6209 
6210  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6211  assert(nodedata != NULL);
6212 
6213  left = SCIPbtnodeGetLeftchild(node);
6214  assert(left != NULL);
6215 
6216  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6217  assert(leftdata != NULL);
6218 
6219  right = SCIPbtnodeGetRightchild(node);
6220  assert(right != NULL);
6221 
6222  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6223  assert(rightdata != NULL);
6224 
6225  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6226  assert(nodedata != NULL);
6227 
6228  assert(nodedata->enveloptheta != -1);
6229  assert(rightdata->energytheta != -1);
6230 
6231  if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6232  {
6233  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6234  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6235  }
6236  else
6237  {
6238  assert(rightdata->enveloptheta != -1);
6239  assert(nodedata->enveloptheta == rightdata->enveloptheta);
6240  traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6241  }
6242  }
6243 }
6244 
6245 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6246 static
6247 void traceLambdaEnergy(
6248  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6249  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6250  int* nelements, /**< pointer to store the number of elements in omega set */
6251  int* est, /**< pointer to store the earliest start time of the omega set */
6252  int* lct, /**< pointer to store the latest start time of the omega set */
6253  int* energy /**< pointer to store the energy of the omega set */
6254  )
6255 {
6256  SCIP_BTNODE* left;
6257  SCIP_BTNODE* right;
6258  SCIP_NODEDATA* nodedata;
6259  SCIP_NODEDATA* leftdata;
6260  SCIP_NODEDATA* rightdata;
6261 
6262  assert(node != NULL);
6263 
6264  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6265  assert(nodedata != NULL);
6266 
6267  /* check if the node is a leaf */
6268  if( SCIPbtnodeIsLeaf(node) )
6269  return;
6270 
6271  left = SCIPbtnodeGetLeftchild(node);
6272  assert(left != NULL);
6273 
6274  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6275  assert(leftdata != NULL);
6276 
6277  right = SCIPbtnodeGetRightchild(node);
6278  assert(right != NULL);
6279 
6280  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6281  assert(rightdata != NULL);
6282 
6283  assert(nodedata->energylambda != -1);
6284  assert(rightdata->energytheta != -1);
6285 
6286  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6287  {
6288  traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6289  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6290  }
6291  else
6292  {
6293  assert(leftdata->energytheta != -1);
6294  assert(rightdata->energylambda != -1);
6295  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6296 
6297  collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6298  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6299  }
6300 }
6301 
6302 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6303 static
6304 void traceLambdaEnvelop(
6305  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6306  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6307  int* nelements, /**< pointer to store the number of elements in omega set */
6308  int* est, /**< pointer to store the earliest start time of the omega set */
6309  int* lct, /**< pointer to store the latest start time of the omega set */
6310  int* energy /**< pointer to store the energy of the omega set */
6311  )
6312 {
6313  SCIP_BTNODE* left;
6314  SCIP_BTNODE* right;
6315  SCIP_NODEDATA* nodedata;
6316  SCIP_NODEDATA* leftdata;
6317  SCIP_NODEDATA* rightdata;
6318 
6319  assert(node != NULL);
6320 
6321  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6322  assert(nodedata != NULL);
6323 
6324  /* check if the node is a leaf */
6325  if( SCIPbtnodeIsLeaf(node) )
6326  {
6327  assert(!nodedata->intheta);
6328  return;
6329  }
6330 
6331  left = SCIPbtnodeGetLeftchild(node);
6332  assert(left != NULL);
6333 
6334  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6335  assert(leftdata != NULL);
6336 
6337  right = SCIPbtnodeGetRightchild(node);
6338  assert(right != NULL);
6339 
6340  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6341  assert(rightdata != NULL);
6342 
6343  assert(nodedata->enveloplambda != -1);
6344  assert(rightdata->energytheta != -1);
6345 
6346  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6347  {
6348  traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6349  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6350  }
6351  else
6352  {
6353  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6354  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6355  {
6356  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6357  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6358  }
6359  else
6360  {
6361  assert(rightdata->enveloplambda != -1);
6362  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6363  traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6364  }
6365  }
6366 }
6367 
6368 /** compute the energy contribution by job which corresponds to the given leaf */
6369 static
6371  SCIP_BTNODE* node /**< leaf */
6372  )
6373 {
6374  SCIP_NODEDATA* nodedata;
6375  int duration;
6376 
6377  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6378  assert(nodedata != NULL);
6379  assert(nodedata->var != NULL);
6380 
6381  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6382  assert(duration > 0);
6383 
6384  SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6386  SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6387 
6388  /* return energy which is contributed by the start time variable */
6389  return nodedata->demand * duration;
6390 }
6391 
6392 /** comparison method for two node data w.r.t. the earliest start time */
6393 static
6394 SCIP_DECL_SORTPTRCOMP(compNodeEst)
6396  int est1;
6397  int est2;
6398 
6399  est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6400  est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6401 
6402  return (est1 - est2);
6403 }
6404 
6405 /** comparison method for two node data w.r.t. the latest completion time */
6406 static
6407 SCIP_DECL_SORTPTRCOMP(compNodedataLct)
6409  int lct1;
6410  int lct2;
6411 
6412  lct1 = ((SCIP_NODEDATA*)elem1)->lct;
6413  lct2 = ((SCIP_NODEDATA*)elem2)->lct;
6414 
6415  return (lct1 - lct2);
6416 }
6417 
6418 
6419 /** an overload was detected; initialized conflict analysis, add an initial reason
6420  *
6421  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6422  */
6423 static
6425  SCIP* scip, /**< SCIP data structure */
6426  SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6427  int capacity, /**< cumulative capacity */
6428  int nleaves, /**< number of responsible leaves */
6429  int est, /**< earliest start time of the ...... */
6430  int lct, /**< latest completly time of the .... */
6431  int reportedenergy, /**< energy which already reported */
6432  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6433  int shift, /**< shift applied to all jobs before adding them to the tree */
6434  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6435  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6436  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6437  )
6438 {
6439  SCIP_Longint energy;
6440  int j;
6441 
6442  /* do nothing if conflict analysis is not applicable */
6444  return SCIP_OKAY;
6445 
6446  SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6447 
6448  /* compute energy of initial time window */
6449  energy = ((SCIP_Longint) lct - est) * capacity;
6450 
6451  /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6452  SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6453 
6454  /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6455  * thereby, compute the time window of interest
6456  */
6457  for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6458  {
6459  SCIP_NODEDATA* nodedata;
6460 
6461  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6462  assert(nodedata != NULL);
6463 
6464  reportedenergy += computeEnergyContribution(leaves[j]);
6465 
6466  /* adjust energy if the earliest start time decrease */
6467  if( nodedata->est < est )
6468  {
6469  est = nodedata->est;
6470  energy = ((SCIP_Longint) lct - est) * capacity;
6471  }
6472  }
6473  assert(reportedenergy > energy);
6474 
6475  SCIPdebugMsg(scip, "time window [%d,%d) available energy %d, required energy %d\n", est, lct, energy, reportedenergy);
6476 
6477  /* initialize conflict analysis */
6479 
6480  /* flip earliest start time and latest completion time */
6481  if( !propest )
6482  {
6483  SCIPswapInts(&est, &lct);
6484 
6485  /* shift earliest start time and latest completion time */
6486  lct = shift - lct;
6487  est = shift - est;
6488  }
6489  else
6490  {
6491  /* shift earliest start time and latest completion time */
6492  lct = lct + shift;
6493  est = est + shift;
6494  }
6495 
6496  nleaves = j;
6497 
6498  /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6499  * overloaded
6500  */
6501  for( j = nleaves-1; j >= 0; --j )
6502  {
6503  SCIP_NODEDATA* nodedata;
6504 
6505  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6506  assert(nodedata != NULL);
6507  assert(nodedata->var != NULL);
6508 
6509  /* check if bound widening should be used */
6510  if( usebdwidening )
6511  {
6512  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6513  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6514  }
6515  else
6516  {
6517  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6518  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6519  }
6520 
6521  if( explanation != NULL )
6522  explanation[nodedata->idx] = TRUE;
6523  }
6524 
6525  (*initialized) = TRUE;
6526 
6527  return SCIP_OKAY;
6528 }
6529 
6530 /** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6531  * responsible interval bounds in *est_omega and *lct_omega
6532  */
6533 static
6534 int computeEstOmegaset(
6535  SCIP* scip, /**< SCIP data structure */
6536  int duration, /**< duration of the job to move */
6537  int demand, /**< demand of the job to move */
6538  int capacity, /**< cumulative capacity */
6539  int est, /**< earliest start time of the omega set */
6540  int lct, /**< latest start time of the omega set */
6541  int energy /**< energy of the omega set */
6542  )
6543 {
6544  int newest;
6545 
6546  newest = 0;
6547 
6548  assert(scip != NULL);
6549 
6550  if( energy > ((SCIP_Longint) capacity - demand) * ((SCIP_Longint) lct - est) )
6551  {
6552  if( energy + (SCIP_Longint) demand * duration > capacity * ((SCIP_Longint) lct - est) )
6553  {
6554  newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6555  newest += est;
6556  }
6557  }
6558 
6559  return newest;
6560 }
6561 
6562 /** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6563  *
6564  * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6565  * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6566  */
6567 static
6569  SCIP* scip, /**< SCIP data structure */
6570  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6571  SCIP_CONS* cons, /**< constraint which is propagated */
6572  SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6573  SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6574  int capacity, /**< cumulative capacity */
6575  int ncands, /**< number of candidates */
6576  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6577  int shift, /**< shift applied to all jobs before adding them to the tree */
6578  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6579  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6580  int* nchgbds, /**< pointer to store the number of bound changes */
6581  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6582  )
6583 {
6584  SCIP_NODEDATA* rootdata;
6585  int j;
6586 
6587  assert(!SCIPbtIsEmpty(tree));
6588 
6589  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6590  assert(rootdata != NULL);
6591 
6592  /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6593  for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6594  {
6595  SCIP_NODEDATA* nodedata;
6596 
6597  if( SCIPbtnodeIsRoot(leaves[j]) )
6598  break;
6599 
6600  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6601  assert(nodedata->est != -1);
6602 
6603  /* check if the root lambda envelop exeeds the available capacity */
6604  while( !(*cutoff) && rootdata->enveloplambda > (SCIP_Longint) capacity * nodedata->lct )
6605  {
6606  SCIP_BTNODE** omegaset;
6607  SCIP_BTNODE* leaf;
6608  SCIP_NODEDATA* leafdata;
6609  int nelements;
6610  int energy;
6611  int newest;
6612  int est;
6613  int lct;
6614 
6615  assert(!(*cutoff));
6616 
6617  /* find responsible leaf for the lambda envelope */
6619  assert(leaf != NULL);
6620  assert(SCIPbtnodeIsLeaf(leaf));
6621 
6622  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6623  assert(leafdata != NULL);
6624  assert(!leafdata->intheta);
6625  assert(leafdata->duration > 0);
6626  assert(leafdata->est >= 0);
6627 
6628  /* check if the job has to be removed since its latest completion is to large */
6629  if( leafdata->est + leafdata->duration >= nodedata->lct )
6630  {
6631  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6632 
6633  /* the root might changed therefore we need to collect the new root node data */
6634  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6635  assert(rootdata != NULL);
6636 
6637  continue;
6638  }
6639 
6640  /* compute omega set */
6641  SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6642 
6643  nelements = 0;
6644  est = INT_MAX;
6645  lct = INT_MIN;
6646  energy = 0;
6647 
6648  /* collect the omega set from theta set */
6649  traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6650  assert(nelements > 0);
6651  assert(nelements < ncands);
6652 
6653  newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6654 
6655  /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6656  if( newest > lct )
6657  {
6658  SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6659 
6660  /* analyze over load */
6661  SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6662  conshdlrdata->usebdwidening, initialized, explanation) );
6663  (*cutoff) = TRUE;
6664 
6665  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6666  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6667  }
6668  else if( newest > 0 )
6669  {
6670  SCIP_Bool infeasible;
6671  SCIP_Bool tightened;
6672  INFERINFO inferinfo;
6673 
6674  if( propest )
6675  {
6676  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6677  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6678 
6679  SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6680  SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6681 
6682  SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6683  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6684 
6685  /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6687  }
6688  else
6689  {
6690  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6691  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6692 
6693  SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6694  SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6695 
6696  SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6697  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6698 
6699  /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6701  }
6702 
6703  /* adjust the earliest start time */
6704  if( tightened )
6705  {
6706  leafdata->est = newest;
6707  (*nchgbds)++;
6708  }
6709 
6710  if( infeasible )
6711  {
6712  /* initialize conflict analysis if conflict analysis is applicable */
6714  {
6715  int i;
6716 
6717  SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6718 
6720 
6721  /* add lower and upper bound of variable which leads to the infeasibilty */
6722  SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6723  SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6724 
6725  if( explanation != NULL )
6726  explanation[leafdata->idx] = TRUE;
6727 
6728  /* add lower and upper bound of variable which lead to the infeasibilty */
6729  for( i = 0; i < nelements; ++i )
6730  {
6731  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6732  assert(nodedata != NULL);
6733 
6734  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6735  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6736 
6737  if( explanation != NULL )
6738  explanation[nodedata->idx] = TRUE;
6739  }
6740 
6741  (*initialized) = TRUE;
6742  }
6743 
6744  (*cutoff) = TRUE;
6745 
6746  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6747  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6748  }
6749  }
6750 
6751  /* free omegaset array */
6752  SCIPfreeBufferArray(scip, &omegaset);
6753 
6754  /* delete responsible leaf from lambda */
6755  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6756 
6757  /* the root might changed therefore we need to collect the new root node data */
6758  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6759  assert(rootdata != NULL);
6760  }
6761 
6762  /* move current job j from the theta set into the lambda set */
6763  SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6764  }
6765 
6766  return SCIP_OKAY;
6767 }
6768 
6769 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6770  *
6771  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6772  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6773  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6774  */
6775 static
6777  SCIP* scip, /**< SCIP data structure */
6778  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6779  int nvars, /**< number of start time variables (activities) */
6780  SCIP_VAR** vars, /**< array of start time variables */
6781  int* durations, /**< array of durations */
6782  int* demands, /**< array of demands */
6783  int capacity, /**< cumulative capacity */
6784  int hmin, /**< left bound of time axis to be considered (including hmin) */
6785  int hmax, /**< right bound of time axis to be considered (not including hmax) */
6786  SCIP_CONS* cons, /**< constraint which is propagated */
6787  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6788  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6789  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6790  int* nchgbds, /**< pointer to store the number of bound changes */
6791  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6792  )
6793 {
6794  SCIP_NODEDATA** nodedatas;
6795  SCIP_BTNODE** leaves;
6796  SCIP_BT* tree;
6797 
6798  int totalenergy;
6799  int nnodedatas;
6800  int ninsertcands;
6801  int ncands;
6802 
6803  int shift;
6804  int j;
6805 
6806  assert(scip != NULL);
6807  assert(cons != NULL);
6808  assert(initialized != NULL);
6809  assert(cutoff != NULL);
6810  assert(*cutoff == FALSE);
6811 
6812  SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6813 
6814  SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6815  SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6816 
6817  ncands = 0;
6818  totalenergy = 0;
6819 
6820  SCIP_CALL( SCIPbtCreate(&tree, SCIPblkmem(scip)) );
6821 
6822  /* compute the shift which we apply to compute .... latest completion time of all jobs */
6823  if( propest )
6824  shift = 0;
6825  else
6826  {
6827  shift = 0;
6828 
6829  /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6830  * earliest start time propagation to handle the latest completion times
6831  */
6832  for( j = 0; j < nvars; ++j )
6833  {
6834  int lct;
6835 
6836  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6837  shift = MAX(shift, lct);
6838  }
6839  }
6840 
6841  /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6842  * horizon
6843  */
6844  for( j = 0; j < nvars; ++j )
6845  {
6846  SCIP_NODEDATA* nodedata;
6847  SCIP_VAR* var;
6848  int duration;
6849  int leftadjust;
6850  int rightadjust;
6851  int energy;
6852  int est;
6853  int lct;
6854 
6855  var = vars[j];
6856  assert(var != NULL);
6857 
6858  duration = durations[j];
6859  assert(duration > 0);
6860 
6861  leftadjust = 0;
6862  rightadjust = 0;
6863 
6864  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
6865  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6866 
6867  /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6868  * effective horizon [hmin,hmax)
6869  */
6870  if( conshdlrdata->useadjustedjobs )
6871  {
6872  if( est < hmin )
6873  {
6874  leftadjust = (hmin - est);
6875  est = hmin;
6876  }
6877  if( lct > hmax )
6878  {
6879  rightadjust = (lct - hmax);
6880  lct = hmax;
6881  }
6882 
6883  /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6884  * with the effective time horizon
6885  */
6886  if( duration - leftadjust - rightadjust <= 0 )
6887  continue;
6888  }
6889  else if( est < hmin || lct > hmax )
6890  continue;
6891 
6892  energy = demands[j] * (duration - leftadjust - rightadjust);
6893  assert(energy > 0);
6894 
6895  totalenergy += energy;
6896 
6897  /* flip earliest start time and latest completion time */
6898  if( !propest )
6899  {
6900  SCIPswapInts(&est, &lct);
6901 
6902  /* shift earliest start time and latest completion time */
6903  lct = shift - lct;
6904  est = shift - est;
6905  }
6906  else
6907  {
6908  /* shift earliest start time and latest completion time */
6909  lct = lct - shift;
6910  est = est - shift;
6911  }
6912  assert(est < lct);
6913  assert(est >= 0);
6914  assert(lct >= 0);
6915 
6916  /* create search node data */
6917  SCIP_CALL( createNodedata(scip, &nodedata) );
6918 
6919  /* initialize search node data */
6920  /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6921  nodedata->key = est + j / (2.0 * nvars);
6922  nodedata->var = var;
6923  nodedata->est = est;
6924  nodedata->lct = lct;
6925  nodedata->demand = demands[j];
6926  nodedata->duration = duration;
6927  nodedata->leftadjust = leftadjust;
6928  nodedata->rightadjust = rightadjust;
6929 
6930  /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6931  * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6932  * particular time interval [a,b] against the time interval [0,b].
6933  */
6934  nodedata->enveloptheta = (SCIP_Longint) capacity * est + energy;
6935  nodedata->energytheta = energy;
6936  nodedata->enveloplambda = -1;
6937  nodedata->energylambda = -1;
6938 
6939  nodedata->idx = j;
6940  nodedata->intheta = TRUE;
6941 
6942  nodedatas[ncands] = nodedata;
6943  ncands++;
6944  }
6945 
6946  nnodedatas = ncands;
6947 
6948  /* sort (non-decreasing) the jobs w.r.t. latest completion times */
6949  SCIPsortPtr((void**)nodedatas, compNodedataLct, ncands);
6950 
6951  ninsertcands = 0;
6952 
6953  /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
6954  * the root envelop detects an overload
6955  */
6956  for( j = 0; j < ncands; ++j )
6957  {
6958  SCIP_BTNODE* leaf;
6959  SCIP_NODEDATA* rootdata;
6960 
6961  /* check if the new job opens a time window which size is so large that it offers more energy than the total
6962  * energy of all candidate jobs. If so we skip that one.
6963  */
6964  if( ((SCIP_Longint) nodedatas[j]->lct - nodedatas[j]->est) * capacity >= totalenergy )
6965  {
6966  /* set the earliest start time to minus one to mark that candidate to be not used */
6967  nodedatas[j]->est = -1;
6968  continue;
6969  }
6970 
6971  /* create search node */
6972  SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)nodedatas[j]) );
6973 
6974  /* insert new node into the theta set and updete the envelops */
6975  SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, &nnodedatas) );
6976  assert(nnodedatas <= 2*nvars);
6977 
6978  /* move the inserted candidates together */
6979  leaves[ninsertcands] = leaf;
6980  ninsertcands++;
6981 
6982  assert(!SCIPbtIsEmpty(tree));
6983  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6984  assert(rootdata != NULL);
6985 
6986  /* check if the theta set envelops exceeds the available capacity */
6987  if( rootdata->enveloptheta > (SCIP_Longint) capacity * nodedatas[j]->lct )
6988  {
6989  SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[j]->lct, j);
6990  (*cutoff) = TRUE;
6991 
6992  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6993  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverload++ );
6994 
6995  break;
6996  }
6997  }
6998 
6999  /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
7000  if( *cutoff )
7001  {
7002  int glbenery;
7003  int est;
7004  int lct;
7005 
7006  glbenery = 0;
7007  est = nodedatas[j]->est;
7008  lct = nodedatas[j]->lct;
7009 
7010  /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
7011  * which led to an overload
7012  */
7013  for( j = j+1; j < ncands; ++j )
7014  {
7015  SCIP_NODEDATA* nodedata;
7016  int duration;
7017  int glbest;
7018  int glblct;
7019 
7020  nodedata = nodedatas[j];
7021  assert(nodedata != NULL);
7022 
7023  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
7024 
7025  /* get latest start time */
7026  glbest = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(nodedata->var));
7027  glblct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
7028 
7029  /* check if parts of the jobs run with the time window defined by the last inserted job */
7030  if( glbest < est )
7031  duration -= (est - glbest);
7032 
7033  if( glblct > lct )
7034  duration -= (glblct - lct);
7035 
7036  if( duration > 0 )
7037  {
7038  glbenery += nodedata->demand * duration;
7039 
7040  if( explanation != NULL )
7041  explanation[nodedata->idx] = TRUE;
7042  }
7043  }
7044 
7045  /* analyze the overload */
7046  SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7047  conshdlrdata->usebdwidening, initialized, explanation) );
7048  }
7049  else if( ninsertcands > 1 && conshdlrdata->efinfer )
7050  {
7051  /* if we have more than one job insterted and edge-finding should be performed we do it */
7052  SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7053  propest, shift, initialized, explanation, nchgbds, cutoff) );
7054  }
7055 
7056  /* free the search nodes data */
7057  for( j = nnodedatas - 1; j >= 0; --j )
7058  {
7059  freeNodedata(scip, &nodedatas[j]);
7060  }
7061 
7062  /* free theta tree */
7063  SCIPbtFree(&tree);
7064 
7065  /* free buffer arrays */
7066  SCIPfreeBufferArray(scip, &leaves);
7067  SCIPfreeBufferArray(scip, &nodedatas);
7068 
7069  return SCIP_OKAY;
7070 }
7071 
7072 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7073  *
7074  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7075  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7076  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7077  */
7078 static
7080  SCIP* scip, /**< SCIP data structure */
7081  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7082  int nvars, /**< number of start time variables (activities) */
7083  SCIP_VAR** vars, /**< array of start time variables */
7084  int* durations, /**< array of durations */
7085  int* demands, /**< array of demands */
7086  int capacity, /**< cumulative capacity */
7087  int hmin, /**< left bound of time axis to be considered (including hmin) */
7088  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7089  SCIP_CONS* cons, /**< constraint which is propagated */
7090  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7091  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7092  int* nchgbds, /**< pointer to store the number of bound changes */
7093  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7094  )
7095 {
7096  /* check if a cutoff was already detected */
7097  if( (*cutoff) )
7098  return SCIP_OKAY;
7099 
7100  /* check if at least the basic overload checking should be preformed */
7101  if( !conshdlrdata->efcheck )
7102  return SCIP_OKAY;
7103 
7104  /* check for overload, which may result in a cutoff */
7105  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7106  cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7107 
7108  /* check if a cutoff was detected */
7109  if( (*cutoff) )
7110  return SCIP_OKAY;
7111 
7112  /* check if bound should be infer */
7113  if( !conshdlrdata->efinfer )
7114  return SCIP_OKAY;
7115 
7116  /* check for overload, which may result in a cutoff */
7117  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7118  cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7119 
7120  return SCIP_OKAY;
7121 }
7122 
7123 /** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7124  * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7125  * event points
7126  */
7127 static
7129  SCIP* scip, /**< SCIP data structure */
7130  int nvars, /**< number of start time variables (activities) */
7131  SCIP_VAR** vars, /**< array of start time variables */
7132  int* durations, /**< array of durations */
7133  int* demands, /**< array of demands */
7134  int capacity, /**< cumulative capacity */
7135  int hmin, /**< left bound of time axis to be considered (including hmin) */
7136  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7137  SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7138  )
7139 {
7140  SCIP_VAR* var;
7141  int* starttimes; /* stores when each job is starting */
7142  int* endtimes; /* stores when each job ends */
7143  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7144  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7145 
7146  int lb;
7147  int ub;
7148  int freecapacity; /* remaining capacity */
7149  int curtime; /* point in time which we are just checking */
7150  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7151  int njobs;
7152  int j;
7153 
7154  assert(scip != NULL);
7155  assert(redundant != NULL);
7156 
7157  (*redundant) = TRUE;
7158 
7159  /* if no activities are associated with this cumulative then this constraint is redundant */
7160  if( nvars == 0 )
7161  return SCIP_OKAY;
7162 
7163  assert(vars != NULL);
7164 
7165  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7166  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7167  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7168  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7169 
7170  njobs = 0;
7171 
7172  /* assign variables, start and endpoints to arrays */
7173  for( j = 0; j < nvars; ++j )
7174  {
7175  assert(durations[j] > 0);
7176  assert(demands[j] > 0);
7177 
7178  var = vars[j];
7179  assert(var != NULL);
7180 
7181  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7182  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7183 
7184  /* check if jobs runs completely outside of the effective time horizon */
7185  if( lb >= hmax || ub + durations[j] <= hmin )
7186  continue;
7187 
7188  starttimes[njobs] = MAX(lb, hmin);
7189  startindices[njobs] = j;
7190 
7191  endtimes[njobs] = MIN(ub + durations[j], hmax);
7192  endindices[njobs] = j;
7193  assert(starttimes[njobs] <= endtimes[njobs]);
7194  njobs++;
7195  }
7196 
7197  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7198  SCIPsortIntInt(starttimes, startindices, njobs);
7199  SCIPsortIntInt(endtimes, endindices, njobs);
7200 
7201  endindex = 0;
7202  freecapacity = capacity;
7203 
7204  /* check each start point of a job whether the capacity is violated or not */
7205  for( j = 0; j < njobs; ++j )
7206  {
7207  curtime = starttimes[j];
7208 
7209  /* stop checking, if time point is above hmax */
7210  if( curtime >= hmax )
7211  break;
7212 
7213  /* subtract all capacity needed up to this point */
7214  freecapacity -= demands[startindices[j]];
7215  while( j+1 < njobs && starttimes[j+1] == curtime )
7216  {
7217  ++j;
7218  freecapacity -= demands[startindices[j]];
7219  }
7220 
7221  /* free all capacity usages of jobs the are no longer running */
7222  while( endtimes[endindex] <= curtime )
7223  {
7224  freecapacity += demands[endindices[endindex]];
7225  ++endindex;
7226  }
7227  assert(freecapacity <= capacity);
7228 
7229  /* check freecapacity to be smaller than zero */
7230  if( freecapacity < 0 && curtime >= hmin )
7231  {
7232  (*redundant) = FALSE;
7233  break;
7234  }
7235  } /*lint --e{850}*/
7236 
7237  /* free all buffer arrays */
7238  SCIPfreeBufferArray(scip, &endindices);
7239  SCIPfreeBufferArray(scip, &startindices);
7240  SCIPfreeBufferArray(scip, &endtimes);
7241  SCIPfreeBufferArray(scip, &starttimes);
7242 
7243  return SCIP_OKAY;
7244 }
7245 
7246 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7247  * completion time
7248  */
7249 static
7251  SCIP* scip, /**< SCIP data structure */
7252  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7253  SCIP_PROFILE* profile, /**< resource profile */
7254  int nvars, /**< number of variables (jobs) */
7255  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7256  int* durations, /**< array containing corresponding durations */
7257  int* demands, /**< array containing corresponding demands */
7258  int capacity, /**< cumulative capacity */
7259  int hmin, /**< left bound of time axis to be considered (including hmin) */
7260  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7261  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7262  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7263  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7264  )
7265 {
7266  int v;
7267 
7268  /* insert all cores */
7269  for( v = 0; v < nvars; ++v )
7270  {
7271  SCIP_VAR* var;
7272  SCIP_Bool infeasible;
7273  int duration;
7274  int demand;
7275  int begin;
7276  int end;
7277  int est;
7278  int lst;
7279  int pos;
7280 
7281  var = vars[v];
7282  assert(var != NULL);
7283  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(var)));
7284  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(var)));
7285 
7286  duration = durations[v];
7287  assert(duration > 0);
7288 
7289  demand = demands[v];
7290  assert(demand > 0);
7291 
7292  /* collect earliest and latest start time */
7293  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7294  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7295 
7296  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7297  if( lst + duration <= hmin || est >= hmax )
7298  continue;
7299 
7300  /* compute core interval w.r.t. effective time horizon */
7301  begin = MAX(hmin, lst);
7302  end = MIN(hmax, est + duration);
7303 
7304  /* check if a core exists */
7305  if( begin >= end )
7306  continue;
7307 
7308  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7309  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7310 
7311  /* insert the core into core resource profile (complexity O(log n)) */
7312  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7313 
7314  /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7315  if( infeasible )
7316  {
7317  assert(begin <= SCIPprofileGetTime(profile, pos));
7318  assert(end > SCIPprofileGetTime(profile, pos));
7319 
7320  /* use conflict analysis to analysis the core insertion which was infeasible */
7321  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7322  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7323 
7324  if( explanation != NULL )
7325  explanation[v] = TRUE;
7326 
7327  (*cutoff) = TRUE;
7328 
7329  /* for the statistic we count the number of times a cutoff was detected due the time-time */
7330  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
7331 
7332  break;
7333  }
7334  }
7335 
7336  return SCIP_OKAY;
7337 }
7338 
7339 /** propagate the cumulative condition */
7340 static
7342  SCIP* scip, /**< SCIP data structure */
7343  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7344  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7345  int nvars, /**< number of start time variables (activities) */
7346  SCIP_VAR** vars, /**< array of start time variables */
7347  int* durations, /**< array of durations */
7348  int* demands, /**< array of demands */
7349  int capacity, /**< cumulative capacity */
7350  int hmin, /**< left bound of time axis to be considered (including hmin) */
7351  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7352  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7353  int* nchgbds, /**< pointer to store the number of bound changes */
7354  SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7355  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7356  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7357  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7358  )
7359 {
7360  SCIP_PROFILE* profile;
7361 
7362  SCIP_RETCODE retcode = SCIP_OKAY;
7363 
7364  assert(nchgbds != NULL);
7365  assert(initialized != NULL);
7366  assert(cutoff != NULL);
7367  assert(!(*cutoff));
7368 
7369  /**@todo avoid always sorting the variable array */
7370 
7371  /* check if the constraint is redundant */
7372  SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7373 
7374  if( *redundant )
7375  return SCIP_OKAY;
7376 
7377  /* create an empty resource profile for profiling the cores of the jobs */
7378  SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7379 
7380  /* create core profile (compulsory parts) */
7381  SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7382  initialized, explanation, cutoff), TERMINATE );
7383 
7384  /* propagate the job cores until nothing else can be detected */
7385  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7386  {
7387  SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7388  nchgbds, initialized, explanation, cutoff), TERMINATE );
7389  }
7390 
7391  /* run edge finding propagator */
7392  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7393  {
7394  SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7395  cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7396  }
7397 
7398  /* run time-table edge-finding propagator */
7399  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7400  {
7401  SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7402  nchgbds, initialized, explanation, cutoff), TERMINATE );
7403  }
7404  /* free resource profile */
7405 TERMINATE:
7406  SCIPprofileFree(&profile);
7407 
7408  return retcode;
7409 }
7410 
7411 /** propagate the cumulative constraint */
7412 static
7414  SCIP* scip, /**< SCIP data structure */
7415  SCIP_CONS* cons, /**< constraint to propagate */
7416  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7417  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7418  int* nchgbds, /**< pointer to store the number of bound changes */
7419  int* ndelconss, /**< pointer to store the number of deleted constraints */
7420  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7421  )
7422 {
7423  SCIP_CONSDATA* consdata;
7424  SCIP_Bool initialized;
7425  SCIP_Bool redundant;
7426  int oldnchgbds;
7427 
7428  assert(scip != NULL);
7429  assert(cons != NULL);
7430 
7431  consdata = SCIPconsGetData(cons);
7432  assert(consdata != NULL);
7433 
7434  oldnchgbds = *nchgbds;
7435  initialized = FALSE;
7436  redundant = FALSE;
7437 
7438  if( SCIPconsIsDeleted(cons) )
7439  {
7440  assert(SCIPinProbing(scip));
7441  return SCIP_OKAY;
7442  }
7443 
7444  /* if the constraint marked to be propagated, do nothing */
7445  if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7446  return SCIP_OKAY;
7447 
7448  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7449  consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7450  consdata->hmin, consdata->hmax, cons,
7451  nchgbds, &redundant, &initialized, NULL, cutoff) );
7452 
7453  if( redundant )
7454  {
7455  SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7456  SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7457 
7458  if( !SCIPinProbing(scip) )
7459  {
7460  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7461  (*ndelconss)++;
7462  }
7463  }
7464  else
7465  {
7466  if( initialized )
7467  {
7468  /* run conflict analysis since it was initialized */
7469  assert(*cutoff == TRUE);
7470  SCIPdebugMsg(scip, "start conflict analysis\n");
7471  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7472  }
7473 
7474  /* if successful, reset age of constraint */
7475  if( *cutoff || *nchgbds > oldnchgbds )
7476  {
7477  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7478  }
7479  else
7480  {
7481  /* mark the constraint to be propagated */
7482  consdata->propagated = TRUE;
7483  }
7484  }
7485 
7486  return SCIP_OKAY;
7487 }
7488 
7489 /** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7490  * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7491  * be realize as domain reduction. Otherwise we do nothing
7492  */
7493 static
7495  SCIP* scip, /**< SCIP data structure */
7496  SCIP_VAR** vars, /**< problem variables */
7497  int nvars, /**< number of problem variables */
7498  int probingpos, /**< variable number to apply probing on */
7499  SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7500  SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7501  SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7502  SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7503  SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7504  SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7505  SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7506  SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7507  SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7508  SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7509  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7510  SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7511  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7512  )
7513 {
7514  SCIP_VAR* var;
7515  SCIP_Bool tightened;
7516 
7517  assert(probingpos >= 0);
7518  assert(probingpos < nvars);
7519  assert(success != NULL);
7520  assert(cutoff != NULL);
7521 
7522  var = vars[probingpos];
7523  assert(var != NULL);
7524  assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7525  assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7526  assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7527  assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7528 
7529  (*success) = FALSE;
7530 
7531  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7532  return SCIP_OKAY;
7533 
7534  /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7535  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7536  leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7537 
7538  if( (*cutoff) )
7539  {
7540  /* note that cutoff may occur if presolving has not been executed fully */
7541  SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7542 
7543  if( tightened )
7544  {
7545  (*success) =TRUE;
7546  (*nfixedvars)++;
7547  }
7548 
7549  return SCIP_OKAY;
7550  }
7551 
7552  /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7553  * presolving has not been executed fully
7554  */
7555  if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7556  {
7557  /* note that cutoff may occur if presolving has not been executed fully */
7558  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7559 
7560  if( tightened )
7561  {
7562  (*success) = TRUE;
7563  (*nfixedvars)++;
7564  }
7565 
7566  return SCIP_OKAY;
7567  }
7568 
7569  /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7570  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7571  rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7572 
7573  if( (*cutoff) )
7574  {
7575  /* note that cutoff may occur if presolving has not been executed fully */
7576  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7577 
7578  if( tightened )
7579  {
7580  (*success) =TRUE;
7581  (*nfixedvars)++;
7582  }
7583 
7584  return SCIP_OKAY;
7585  }
7586 
7587  return SCIP_OKAY;
7588 }
7589 
7590 /** is it possible, to round variable down w.r.t. objective function */
7591 static
7593  SCIP* scip, /**< SCIP data structure */
7594  SCIP_VAR* var, /**< problem variable */
7595  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7596  )
7597 {
7598  SCIP_Real objval;
7599  int scalar;
7600 
7601  assert(roundable != NULL);
7602 
7603  *roundable = TRUE;
7604 
7605  /* a fixed variable can be definition always be safely rounded */
7607  return SCIP_OKAY;
7608 
7609  /* in case the variable is not active we need to check the object coefficient of the active variable */
7610  if( !SCIPvarIsActive(var) )
7611  {
7612  SCIP_VAR* actvar;
7613  int constant;
7614 
7615  actvar = var;
7616 
7617  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7618  assert(scalar != 0);
7619 
7620  objval = scalar * SCIPvarGetObj(actvar);
7621  } /*lint !e438*/
7622  else
7623  {
7624  scalar = 1;
7625  objval = SCIPvarGetObj(var);
7626  }
7627 
7628  /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7629  * (the transformed problem is always a minimization problem)
7630  *
7631  * @note that we need to check this condition w.r.t. active variable space
7632  */
7633  if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7634  *roundable = FALSE;
7635 
7636  return SCIP_OKAY;
7637 }
7638 
7639 /** is it possible, to round variable up w.r.t. objective function */
7640 static
7642  SCIP* scip, /**< SCIP data structure */
7643  SCIP_VAR* var, /**< problem variable */
7644  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7645  )
7646 {
7647  SCIP_Real objval;
7648  int scalar;
7649 
7650  assert(roundable != NULL);
7651 
7652  *roundable = TRUE;
7653 
7654  /* a fixed variable can be definition always be safely rounded */
7656  return SCIP_OKAY;
7657 
7658  /* in case the variable is not active we need to check the object coefficient of the active variable */
7659  if( !SCIPvarIsActive(var) )
7660  {
7661  SCIP_VAR* actvar;
7662  int constant;
7663 
7664  actvar = var;
7665 
7666  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7667  assert(scalar != 0);
7668 
7669  objval = scalar * SCIPvarGetObj(actvar);
7670  } /*lint !e438*/
7671  else
7672  {
7673  scalar = 1;
7674  objval = SCIPvarGetObj(var);
7675  }
7676 
7677  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7678  * (the transformed problem is always a minimization problem)
7679  *
7680  * @note that we need to check this condition w.r.t. active variable space
7681  */
7682  if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7683  *roundable = FALSE;
7684 
7685  return SCIP_OKAY;
7686 }
7687 
7688 /** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7689  * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7690  * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7691  * the only one locking this variable in the corresponding direction.
7692  */
7693 static
7695  SCIP* scip, /**< SCIP data structure */
7696  SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7697  int nconss, /**< number of cumulative constraints */
7698  SCIP_Bool local, /**< use local bounds effective horizon? */
7699  int* alternativelbs, /**< alternative lower bounds */
7700  int* alternativeubs, /**< alternative lower bounds */
7701  int* downlocks, /**< number of constraints with down lock participating by the computation */
7702  int* uplocks /**< number of constraints with up lock participating by the computation */
7703  )
7704 {
7705  int nvars;
7706  int c;
7707  int v;
7708 
7709  for( c = 0; c < nconss; ++c )
7710  {
7711  SCIP_CONSDATA* consdata;
7712  SCIP_CONS* cons;
7713  SCIP_VAR* var;
7714  int hmin;
7715  int hmax;
7716 
7717  cons = conss[c];
7718  assert(cons != NULL);
7719 
7720  /* ignore constraints which are already deletet and those which are not check constraints */
7721  if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7722  continue;
7723 
7724  consdata = SCIPconsGetData(cons);
7725  assert(consdata != NULL);
7726  assert(consdata->nvars > 1);
7727 
7728  /* compute the hmin and hmax */
7729  if( local )
7730  {
7731  SCIP_PROFILE* profile;
7732  SCIP_RETCODE retcode;
7733 
7734  /* create empty resource profile with infinity resource capacity */
7735  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7736 
7737  /* create worst case resource profile */
7738  retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
7739 
7740  hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7741  hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7742 
7743  /* free worst case profile */
7744  SCIPprofileFree(&profile);
7745 
7746  if( retcode != SCIP_OKAY )
7747  return retcode;
7748  }
7749  else
7750  {
7751  hmin = consdata->hmin;
7752  hmax = consdata->hmax;
7753  }
7754 
7755  consdata = SCIPconsGetData(cons);
7756  assert(consdata != NULL);
7757 
7758  nvars = consdata->nvars;
7759 
7760  for( v = 0; v < nvars; ++v )
7761  {
7762  int scalar;
7763  int constant;
7764  int idx;
7765 
7766  var = consdata->vars[v];
7767  assert(var != NULL);
7768 
7769  /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7770  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR);
7771 
7772  /* ignore variable locally fixed variables */
7773  if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7774  continue;
7775 
7776  SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7777  idx = SCIPvarGetProbindex(var);
7778  assert(idx >= 0);
7779 
7780  /* first check lower bound fixing */
7781  if( consdata->downlocks[v] )
7782  {
7783  int ect;
7784  int est;
7785 
7786  /* the variable has a down locked */
7787  est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7788  ect = est + consdata->durations[v];
7789 
7790  if( ect <= hmin || hmin >= hmax )
7791  downlocks[idx]++;
7792  else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7793  {
7794  alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7795  downlocks[idx]++;
7796  }
7797  }
7798 
7799  /* second check upper bound fixing */
7800  if( consdata->uplocks[v] )
7801  {
7802  int duration;
7803  int lct;
7804  int lst;
7805 
7806  duration = consdata->durations[v];
7807 
7808  /* the variable has a up lock locked */
7809  lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7810  lct = lst + duration;
7811 
7812  if( lst >= hmax || hmin >= hmax )
7813  uplocks[idx]++;
7814  else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7815  {
7816  alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7817  uplocks[idx]++;
7818  }
7819  }
7820  }
7821  }
7822 
7823  return SCIP_OKAY;
7824 }
7825 
7826 /** apply all fixings which are given by the alternative bounds */
7827 static
7829  SCIP* scip, /**< SCIP data structure */
7830  SCIP_VAR** vars, /**< array of active variables */
7831  int nvars, /**< number of active variables */
7832  int* alternativelbs, /**< alternative lower bounds */
7833  int* alternativeubs, /**< alternative lower bounds */
7834  int* downlocks, /**< number of constraints with down lock participating by the computation */
7835  int* uplocks, /**< number of constraints with up lock participating by the computation */
7836  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7837  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7838  )
7839 {
7840  SCIP_Real* downimpllbs;
7841  SCIP_Real* downimplubs;
7842  SCIP_Real* downproplbs;
7843  SCIP_Real* downpropubs;
7844  SCIP_Real* upimpllbs;
7845  SCIP_Real* upimplubs;
7846  SCIP_Real* upproplbs;
7847  SCIP_Real* uppropubs;
7848  int v;
7849 
7850  /* get temporary memory for storing probing results */
7851  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7852  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7853  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7854  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7855  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7856  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7857  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7858  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7859 
7860  for( v = 0; v < nvars; ++v )
7861  {
7862  SCIP_VAR* var;
7863  SCIP_Bool infeasible;
7864  SCIP_Bool fixed;
7865  SCIP_Bool roundable;
7866  int ub;
7867  int lb;
7868 
7869  var = vars[v];
7870  assert(var != NULL);
7871 
7872  /* ignore variables for which no alternative bounds have been computed */
7873  if( alternativelbs[v] == INT_MAX && alternativeubs[v] == INT_MIN )
7874  continue;
7875 
7876  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7877  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7878 
7879  /* ignore fixed variables */
7880  if( ub - lb <= 0 )
7881  continue;
7882 
7883  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
7884  {
7885  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7886 
7887  if( roundable )
7888  {
7889  if( alternativelbs[v] > ub )
7890  {
7891  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7892  assert(!infeasible);
7893  assert(fixed);
7894 
7895  (*nfixedvars)++;
7896 
7897  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7898  * constraints
7899  */
7900  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7901  }
7902  else
7903  {
7904  SCIP_Bool success;
7905 
7906  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7907  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7908  * infeasible we can apply the dual reduction; otherwise we do nothing
7909  */
7910  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7911  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7912  nfixedvars, &success, cutoff) );
7913 
7914  if( success )
7915  {
7916  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7917  }
7918  }
7919  }
7920  }
7921 
7922  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7923  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7924 
7925  /* ignore fixed variables */
7926  if( ub - lb <= 0 )
7927  continue;
7928 
7929  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
7930  {
7931  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7932 
7933  if( roundable )
7934  {
7935  if( alternativeubs[v] < lb )
7936  {
7937  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
7938  assert(!infeasible);
7939  assert(fixed);
7940 
7941  (*nfixedvars)++;
7942 
7943  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7944  * constraints
7945  */
7946  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7947  }
7948  else
7949  {
7950  SCIP_Bool success;
7951 
7952  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7953  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7954  * infeasible we can apply the dual reduction; otherwise we do nothing
7955  */
7956  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
7957  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7958  nfixedvars, &success, cutoff) );
7959 
7960  if( success )
7961  {
7962  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7963  }
7964  }
7965  }
7966  }
7967  }
7968 
7969  /* free temporary memory */
7970  SCIPfreeBufferArray(scip, &uppropubs);
7971  SCIPfreeBufferArray(scip, &upproplbs);
7972  SCIPfreeBufferArray(scip, &upimplubs);
7973  SCIPfreeBufferArray(scip, &upimpllbs);
7974  SCIPfreeBufferArray(scip, &downpropubs);
7975  SCIPfreeBufferArray(scip, &downproplbs);
7976  SCIPfreeBufferArray(scip, &downimplubs);
7977  SCIPfreeBufferArray(scip, &downimpllbs);
7978 
7979  return SCIP_OKAY;
7980 }
7981 
7982 /** propagate all constraints together */
7983 static
7985  SCIP* scip, /**< SCIP data structure */
7986  SCIP_CONS** conss, /**< all cumulative constraint */
7987  int nconss, /**< number of cumulative constraints */
7988  SCIP_Bool local, /**< use local bounds effective horizon? */
7989  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7990  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
7991  SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
7992  )
7993 { /*lint --e{715}*/
7994  SCIP_VAR** vars;
7995  int* downlocks;
7996  int* uplocks;
7997  int* alternativelbs;
7998  int* alternativeubs;
7999  int oldnfixedvars;
8000  int nvars;
8001  int v;
8002 
8003  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
8004  return SCIP_OKAY;
8005 
8006  nvars = SCIPgetNVars(scip);
8007  oldnfixedvars = *nfixedvars;
8008 
8009  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
8010  SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
8011  SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
8012  SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
8013  SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
8014 
8015  /* initialize arrays */
8016  for( v = 0; v < nvars; ++v )
8017  {
8018  downlocks[v] = 0;
8019  uplocks[v] = 0;
8020  alternativelbs[v] = INT_MAX;
8021  alternativeubs[v] = INT_MIN;
8022  }
8023 
8024  /* compute alternative bounds */
8025  SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
8026 
8027  /* apply fixing which result of the alternative bounds directly */
8028  SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
8029  nfixedvars, cutoff) );
8030 
8031  if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
8032  {
8033  SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
8034  }
8035 
8036  /* free all buffers */
8037  SCIPfreeBufferArray(scip, &alternativeubs);
8038  SCIPfreeBufferArray(scip, &alternativelbs);
8039  SCIPfreeBufferArray(scip, &uplocks);
8040  SCIPfreeBufferArray(scip, &downlocks);
8041  SCIPfreeBufferArray(scip, &vars);
8042 
8043  return SCIP_OKAY;
8044 }
8045 
8046 /**@} */
8047 
8048 /**@name Linear relaxations
8049  *
8050  * @{
8051  */
8052 
8053 /** creates covering cuts for jobs violating resource constraints */
8054 static
8056  SCIP* scip, /**< SCIP data structure */
8057  SCIP_CONS* cons, /**< constraint to be checked */
8058  int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8059  int time /**< at this point in time covering constraints are valid */
8060  )
8061 {
8062  SCIP_CONSDATA* consdata;
8063  SCIP_ROW* row;
8064  int* flexibleids;
8065  int* demands;
8066 
8067  char rowname[SCIP_MAXSTRLEN];
8068 
8069  int remainingcap;
8070  int smallcoversize; /* size of a small cover */
8071  int bigcoversize; /* size of a big cover */
8072  int nvars;
8073 
8074  int nflexible;
8075  int sumdemand; /* demand of all jobs up to a certain index */
8076  int j;
8077 
8078  assert(cons != NULL);
8079 
8080  /* get constraint data structure */
8081  consdata = SCIPconsGetData(cons);
8082  assert(consdata != NULL );
8083 
8084  nvars = consdata->nvars;
8085 
8086  /* sort jobs according to demands */
8087  SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8088  SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8089 
8090  nflexible = 0;
8091  remainingcap = consdata->capacity;
8092 
8093  /* get all jobs intersecting point 'time' with their bounds */
8094  for( j = 0; j < nvars; ++j )
8095  {
8096  int ub;
8097 
8098  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8099 
8100  /* only add jobs to array if they intersect with point 'time' */
8101  if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8102  {
8103  /* if job is fixed, capacity has to be decreased */
8104  if( startvalues[j] == ub )
8105  {
8106  remainingcap -= consdata->demands[j];
8107  }
8108  else
8109  {
8110  demands[nflexible] = consdata->demands[j];
8111  flexibleids[nflexible] = j;
8112  ++nflexible;
8113  }
8114  }
8115  }
8116  assert(remainingcap >= 0);
8117 
8118  /* sort demands and job ids */
8119  SCIPsortIntInt(demands, flexibleids, nflexible);
8120 
8121  /*
8122  * version 1:
8123  * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8124  * erzeuge cover constraint
8125  *
8126  */
8127 
8128  /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8129  sumdemand = 0;
8130  j = 0;
8131 
8132  while( j < nflexible && sumdemand <= remainingcap )
8133  {
8134  sumdemand += demands[j];
8135  j++;
8136  }
8137 
8138  /* j jobs form a conflict, set coversize to 'j - 1' */
8139  bigcoversize = j-1;
8140  assert(sumdemand > remainingcap);
8141  assert(bigcoversize < nflexible);
8142 
8143  /* - create a row for all jobs and their binary variables.
8144  * - at most coversize many binary variables of jobs can be set to one
8145  */
8146 
8147  /* construct row name */
8148  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8149  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8150  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8151  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8152 
8153  for( j = 0; j < nflexible; ++j )
8154  {
8155  SCIP_VAR** binvars;
8156  SCIP_Real* vals;
8157  int nbinvars;
8158  int idx;
8159  int start;
8160  int end;
8161  int lb;
8162  int ub;
8163  int b;
8164 
8165  idx = flexibleids[j];
8166 
8167  /* get and add binvars into var array */
8168  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8169  assert(nbinvars != 0);
8170 
8171  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8172  assert(vals != NULL);
8173 
8174  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8175  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8176 
8177  /* compute start and finishing time */
8178  start = time - consdata->durations[idx] + 1;
8179  end = MIN(time, ub);
8180 
8181  /* add all neccessary binary variables */
8182  for( b = 0; b < nbinvars; ++b )
8183  {
8184  if( vals[b] < start || vals[b] < lb )
8185  continue;
8186 
8187  if( vals[b] > end )
8188  break;
8189 
8190  assert(binvars[b] != NULL);
8191  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8192  }
8193  }
8194 
8195  /* insert and release row */
8196  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8197 
8198  if( consdata->bcoverrowssize == 0 )
8199  {
8200  consdata->bcoverrowssize = 10;
8201  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8202  }
8203  if( consdata->nbcoverrows == consdata->bcoverrowssize )
8204  {
8205  consdata->bcoverrowssize *= 2;
8206  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8207  }
8208 
8209  consdata->bcoverrows[consdata->nbcoverrows] = row;
8210  consdata->nbcoverrows++;
8211 
8212  /*
8213  * version 2:
8214  * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8215  * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8216  */
8217  /* find maximum number of jobs that can run in parallel (= coversize -1) */
8218  sumdemand = 0;
8219  j = nflexible -1;
8220  while( sumdemand <= remainingcap )
8221  {
8222  assert(j >= 0);
8223  sumdemand += demands[j];
8224  j--;
8225  }
8226 
8227  smallcoversize = nflexible - (j + 1) - 1;
8228  while( j > 0 && demands[j] == demands[nflexible-1] )
8229  --j;
8230 
8231  assert(smallcoversize < nflexible);
8232 
8233  if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8234  {
8235  /* construct row name */
8236  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8237  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8238  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8239  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8240 
8241  /* filter binary variables for each unfixed job */
8242  for( j = j + 1; j < nflexible; ++j )
8243  {
8244  SCIP_VAR** binvars;
8245  SCIP_Real* vals;
8246  int nbinvars;
8247  int idx;
8248  int start;
8249  int end;
8250  int lb;
8251  int ub;
8252  int b;
8253 
8254  idx = flexibleids[j];
8255 
8256  /* get and add binvars into var array */
8257  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8258  assert(nbinvars != 0);
8259 
8260  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8261  assert(vals != NULL);
8262 
8263  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8264  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8265 
8266  /* compute start and finishing time */
8267  start = time - consdata->durations[idx] + 1;
8268  end = MIN(time, ub);
8269 
8270  /* add all neccessary binary variables */
8271  for( b = 0; b < nbinvars; ++b )
8272  {
8273  if( vals[b] < start || vals[b] < lb )
8274  continue;
8275 
8276  if( vals[b] > end )
8277  break;
8278 
8279  assert(binvars[b] != NULL);
8280  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8281  }
8282  }
8283 
8284  /* insert and release row */
8285  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8286  if( consdata->scoverrowssize == 0 )
8287  {
8288  consdata->scoverrowssize = 10;
8289  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8290  }
8291  if( consdata->nscoverrows == consdata->scoverrowssize )
8292  {
8293  consdata->scoverrowssize *= 2;
8294  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8295  }
8296 
8297  consdata->scoverrows[consdata->nscoverrows] = row;
8298  consdata->nscoverrows++;
8299  }
8300 
8301  /* free buffer arrays */
8302  SCIPfreeBufferArray(scip, &flexibleids);
8303  SCIPfreeBufferArray(scip, &demands);
8304 
8305  return SCIP_OKAY;
8306 }
8307 
8308 /** method to construct cover cuts for all points in time */
8309 static
8311  SCIP* scip, /**< SCIP data structure */
8312  SCIP_CONS* cons /**< constraint to be separated */
8313  )
8314 {
8315  SCIP_CONSDATA* consdata;
8316 
8317  int* startvalues; /* stores when each job is starting */
8318  int* endvalues; /* stores when each job ends */
8319  int* startvaluessorted; /* stores when each job is starting */
8320  int* endvaluessorted; /* stores when each job ends */
8321  int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8322  int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8323 
8324  int nvars; /* number of jobs for this constraint */
8325  int freecapacity; /* remaining capacity */
8326  int curtime; /* point in time which we are just checking */
8327  int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8328 
8329  int hmin;
8330  int hmax;
8331 
8332  int j;
8333  int t;
8334 
8335  assert(scip != NULL);
8336  assert(cons != NULL);
8337 
8338  consdata = SCIPconsGetData(cons);
8339  assert(consdata != NULL);
8340 
8341  /* if no activities are associated with this resource then this constraint is redundant */
8342  if( consdata->vars == NULL )
8343  return SCIP_OKAY;
8344 
8345  nvars = consdata->nvars;
8346  hmin = consdata->hmin;
8347  hmax = consdata->hmax;
8348 
8349  SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8350  SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8351  SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8352  SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8353  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8354  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8355 
8356  /* assign start and endpoints to arrays */
8357  for ( j = 0; j < nvars; ++j )
8358  {
8359  startvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8360  startvaluessorted[j] = startvalues[j];
8361 
8362  endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8363  endvaluessorted[j] = endvalues[j];
8364 
8365  startindices[j] = j;
8366  endindices[j] = j;
8367  }
8368 
8369  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8370  * (and sort the indices in the same way) */
8371  SCIPsortIntInt(startvaluessorted, startindices, nvars);
8372  SCIPsortIntInt(endvaluessorted, endindices, nvars);
8373 
8374  endidx = 0;
8375  freecapacity = consdata->capacity;
8376 
8377  /* check each startpoint of a job whether the capacity is kept or not */
8378  for( j = 0; j < nvars; ++j )
8379  {
8380  curtime = startvaluessorted[j];
8381  if( curtime >= hmax )
8382  break;
8383 
8384  /* subtract all capacity needed up to this point */
8385  freecapacity -= consdata->demands[startindices[j]];
8386 
8387  while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8388  {
8389  ++j;
8390  freecapacity -= consdata->demands[startindices[j]];
8391  }
8392 
8393  /* free all capacity usages of jobs the are no longer running */
8394  while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8395  {
8396  freecapacity += consdata->demands[endindices[endidx]];
8397  ++endidx;
8398  }
8399 
8400  assert(freecapacity <= consdata->capacity);
8401  assert(endidx <= nvars);
8402 
8403  /* --> endindex - points to the next job which will finish
8404  * j - points to the last job that has been released
8405  */
8406 
8407  /* check freecapacity to be smaller than zero
8408  * then we will add cover constraints to the MIP
8409  */
8410  if( freecapacity < 0 && curtime >= hmin )
8411  {
8412  int nextprofilechange;
8413 
8414  /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8415  if( j < nvars-1 )
8416  nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8417  else
8418  nextprofilechange = endvaluessorted[endidx];
8419 
8420  nextprofilechange = MIN(nextprofilechange, hmax);
8421 
8422  for( t = curtime; t < nextprofilechange; ++t )
8423  {
8424  SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8425 
8426  /* create covering constraint */
8427  SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8428  }
8429  } /* end if freecapacity > 0 */
8430  } /*lint --e{850}*/
8431 
8432  consdata->covercuts = TRUE;
8433 
8434  /* free all buffer arrays */
8435  SCIPfreeBufferArray(scip, &endindices);
8436  SCIPfreeBufferArray(scip, &startindices);
8437  SCIPfreeBufferArray(scip, &endvaluessorted);
8438  SCIPfreeBufferArray(scip, &startvaluessorted);
8439  SCIPfreeBufferArray(scip, &endvalues);
8440  SCIPfreeBufferArray(scip, &startvalues);
8441 
8442  return SCIP_OKAY;
8443 }
8444 
8445 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8446  * constraint
8447  */
8448 static
8450  SCIP* scip, /**< SCIP data structure */
8451  SCIP_CONS* cons, /**< constraint to be checked */
8452  int* startindices, /**< permutation with rspect to the start times */
8453  int curtime, /**< current point in time */
8454  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8455  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8456  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8457  )
8458 {
8459  SCIP_CONSDATA* consdata;
8460  SCIP_VAR** binvars;
8461  int* coefs;
8462  int nbinvars;
8463  char name[SCIP_MAXSTRLEN];
8464  int capacity;
8465  int b;
8466 
8467  assert(nstarted > nfinished);
8468 
8469  consdata = SCIPconsGetData(cons);
8470  assert(consdata != NULL);
8471  assert(consdata->nvars > 0);
8472 
8473  capacity = consdata->capacity;
8474  assert(capacity > 0);
8475 
8476  nbinvars = 0;
8477  SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8478 
8479  /* construct row name */
8480  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8481 
8482  if( cutsasconss )
8483  {
8484  SCIP_CONS* lincons;
8485 
8486  /* create knapsack constraint for the given time point */
8487  SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8488  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) );
8489 
8490  for( b = 0; b < nbinvars; ++b )
8491  {
8492  SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8493  }
8494 
8495  /* add and release the new constraint */
8496  SCIP_CALL( SCIPaddCons(scip, lincons) );
8497  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8498  }
8499  else
8500  {
8501  SCIP_ROW* row;
8502 
8503  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8504  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8505 
8506  for( b = 0; b < nbinvars; ++b )
8507  {
8508  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8509  }
8510 
8511  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8512  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8513 
8514  if( consdata->demandrowssize == 0 )
8515  {
8516  consdata->demandrowssize = 10;
8517  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8518  }
8519  if( consdata->ndemandrows == consdata->demandrowssize )
8520  {
8521  consdata->demandrowssize *= 2;
8522  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8523  }
8524 
8525  consdata->demandrows[consdata->ndemandrows] = row;
8526  consdata->ndemandrows++;
8527  }
8528 
8529  SCIPfreeBufferArrayNull(scip, &binvars);
8530  SCIPfreeBufferArrayNull(scip, &coefs);
8531 
8532  return SCIP_OKAY;
8533 }
8534 
8535 /** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8536  * row
8537  */
8538 static
8540  SCIP* scip, /**< SCIP data structure */
8541  SCIP_CONS* cons, /**< constraint to be checked */
8542  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8543  )
8544 {
8545  SCIP_CONSDATA* consdata;
8546 
8547  int* starttimes; /* stores when each job is starting */
8548  int* endtimes; /* stores when each job ends */
8549  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8550  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8551 
8552  int nvars; /* number of activities for this constraint */
8553  int freecapacity; /* remaining capacity */
8554  int curtime; /* point in time which we are just checking */
8555  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8556 
8557  int hmin;
8558  int hmax;
8559 
8560  int j;
8561 
8562  assert(scip != NULL);
8563  assert(cons != NULL);
8564 
8565  consdata = SCIPconsGetData(cons);
8566  assert(consdata != NULL);
8567 
8568  nvars = consdata->nvars;
8569 
8570  /* if no activities are associated with this cumulative then this constraint is redundant */
8571  if( nvars == 0 )
8572  return SCIP_OKAY;
8573 
8574  assert(consdata->vars != NULL);
8575 
8576  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8577  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8578  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8579  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8580 
8581  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8582  SCIPconsGetName(cons), nvars);
8583 
8584  /* create event point arrays */
8585  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8586  starttimes, endtimes, startindices, endindices, FALSE);
8587 
8588  endindex = 0;
8589  freecapacity = consdata->capacity;
8590  hmin = consdata->hmin;
8591  hmax = consdata->hmax;
8592 
8593  /* check each startpoint of a job whether the capacity is kept or not */
8594  for( j = 0; j < nvars; ++j )
8595  {
8596  curtime = starttimes[j];
8597  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8598 
8599  if( curtime >= hmax )
8600  break;
8601 
8602  /* remove the capacity requirments for all job which start at the curtime */
8603  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8604 
8605  /* add the capacity requirments for all job which end at the curtime */
8606  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8607 
8608  assert(freecapacity <= consdata->capacity);
8609  assert(endindex <= nvars);
8610 
8611  /* endindex - points to the next job which will finish */
8612  /* j - points to the last job that has been released */
8613 
8614  /* if free capacity is smaller than zero, then add rows to the LP */
8615  if( freecapacity < 0 && curtime >= hmin )
8616  {
8617  int nextstarttime;
8618  int t;
8619 
8620  /* step forward until next job is released and see whether capacity constraint is met or not */
8621  if( j < nvars-1 )
8622  nextstarttime = starttimes[j+1];
8623  else
8624  nextstarttime = endtimes[nvars-1];
8625 
8626  nextstarttime = MIN(nextstarttime, hmax);
8627 
8628  /* create capacity restriction row for current event point */
8629  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8630 
8631  /* create for all points in time between the current event point and next start event point a row if the free
8632  * capacity is still smaller than zero */
8633  for( t = curtime+1 ; t < nextstarttime; ++t )
8634  {
8635  /* add the capacity requirments for all job which end at the curtime */
8636  addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8637 
8638  if( freecapacity < 0 )
8639  {
8640  /* add constraint */
8641  SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8642 
8643  /* create capacity restriction row */
8644  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8645  }
8646  else
8647  break;
8648  }
8649  }
8650  } /*lint --e{850}*/
8651 
8652  /* free all buffer arrays */
8653  SCIPfreeBufferArray(scip, &endindices);
8654  SCIPfreeBufferArray(scip, &startindices);
8655  SCIPfreeBufferArray(scip, &endtimes);
8656  SCIPfreeBufferArray(scip, &starttimes);
8657 
8658  return SCIP_OKAY;
8659 }
8660 
8661 /** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8662  * capacity is larger than the capacity of the cumulative constraint
8663  * - for each necessary point in time:
8664  *
8665  * sum_j sum_t demand_j * x_{j,t} <= capacity
8666  *
8667  * where x(j,t) is the binary variables of job j at time t
8668  */
8669 static
8671  SCIP* scip, /**< SCIP data structure */
8672  SCIP_CONS* cons, /**< cumulative constraint */
8673  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8674  )
8675 {
8676  SCIP_CONSDATA* consdata;
8677 
8678  consdata = SCIPconsGetData(cons);
8679  assert(consdata != NULL);
8680  assert(consdata->demandrows == NULL);
8681  assert(consdata->ndemandrows == 0);
8682 
8683  /* collect the linking constraints */
8684  if( consdata->linkingconss == NULL )
8685  {
8686  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8687  }
8688 
8689  SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8690 
8691  /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8692  if( cutsasconss )
8693  {
8694  if( SCIPconsIsInitial(cons) )
8695  {
8696  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
8697  }
8698  if( SCIPconsIsSeparated(cons) )
8699  {
8700  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
8701  }
8702  if( SCIPconsIsEnforced(cons) )
8703  {
8704  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
8705  }
8706  }
8707 
8708  return SCIP_OKAY;
8709 }
8710 
8711 /** adds linear relaxation of cumulative constraint to the LP */
8712 static
8714  SCIP* scip, /**< SCIP data structure */
8715  SCIP_CONS* cons, /**< cumulative constraint */
8716  SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
8717  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
8718  )
8719 {
8720  SCIP_CONSDATA* consdata;
8721  int r;
8722 
8723  consdata = SCIPconsGetData(cons);
8724  assert(consdata != NULL);
8725 
8726  if( consdata->demandrows == NULL )
8727  {
8728  assert(consdata->ndemandrows == 0);
8729 
8730  SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8731 
8732  return SCIP_OKAY;
8733  }
8734 
8735  for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8736  {
8737  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8738  {
8739  assert(consdata->demandrows[r] != NULL);
8740  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
8741  }
8742  }
8743 
8744  return SCIP_OKAY;
8745 }
8746 
8747 /** checks constraint for violation, and adds it as a cut if possible */
8748 static
8750  SCIP* scip, /**< SCIP data structure */
8751  SCIP_CONS* cons, /**< cumulative constraint to be separated */
8752  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8753  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8754  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8755  )
8756 { /*lint --e{715}*/
8757  SCIP_CONSDATA* consdata;
8758  int ncuts;
8759  int r;
8760 
8761  assert(scip != NULL);
8762  assert(cons != NULL);
8763  assert(separated != NULL);
8764  assert(cutoff != NULL);
8765 
8766  *separated = FALSE;
8767  *cutoff = FALSE;
8768 
8769  consdata = SCIPconsGetData(cons);
8770  assert(consdata != NULL);
8771 
8772  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8773 
8774  if( consdata->demandrows == NULL )
8775  {
8776  assert(consdata->ndemandrows == 0);
8777 
8778  SCIP_CALL( createRelaxation(scip, cons, FALSE) );
8779 
8780  return SCIP_OKAY;
8781  }
8782 
8783  ncuts = 0;
8784 
8785  /* check each row that is not contained in LP */
8786  for( r = 0; r < consdata->ndemandrows; ++r )
8787  {
8788  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8789  {
8790  SCIP_Real feasibility;
8791 
8792  if( sol != NULL )
8793  feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8794  else
8795  feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8796 
8797  if( SCIPisFeasNegative(scip, feasibility) )
8798  {
8799  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
8800  if ( *cutoff )
8801  {
8802  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8803  return SCIP_OKAY;
8804  }
8805  *separated = TRUE;
8806  ncuts++;
8807  }
8808  }
8809  }
8810 
8811  if( ncuts > 0 )
8812  {
8813  SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8814 
8815  /* if successful, reset age of constraint */
8816  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8817  (*separated) = TRUE;
8818  }
8819 
8820  return SCIP_OKAY;
8821 }
8822 
8823 /** checks constraint for violation, and adds it as a cut if possible */
8824 static
8826  SCIP* scip, /**< SCIP data structure */
8827  SCIP_CONS* cons, /**< logic or constraint to be separated */
8828  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8829  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8830  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8831  )
8832 {
8833  SCIP_CONSDATA* consdata;
8834  SCIP_ROW* row;
8835  SCIP_Real minfeasibility;
8836  int r;
8837 
8838  assert(scip != NULL);
8839  assert(cons != NULL);
8840  assert(separated != NULL);
8841  assert(cutoff != NULL);
8842 
8843  *separated = FALSE;
8844  *cutoff = FALSE;
8845 
8846  consdata = SCIPconsGetData(cons);
8847  assert(consdata != NULL);
8848 
8849  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8850 
8851  /* collect the linking constraints */
8852  if( consdata->linkingconss == NULL )
8853  {
8854  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8855  }
8856 
8857  if( !consdata->covercuts )
8858  {
8859  SCIP_CALL( createCoverCuts(scip, cons) );
8860  }
8861 
8862  row = NULL;
8863  minfeasibility = SCIPinfinity(scip);
8864 
8865  /* check each row of small covers that is not contained in LP */
8866  for( r = 0; r < consdata->nscoverrows; ++r )
8867  {
8868  if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8869  {
8870  SCIP_Real feasibility;
8871 
8872  assert(consdata->scoverrows[r] != NULL);
8873  if( sol != NULL )
8874  feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8875  else
8876  feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8877 
8878  if( minfeasibility > feasibility )
8879  {
8880  minfeasibility = feasibility;
8881  row = consdata->scoverrows[r];
8882  }
8883  }
8884  }
8885 
8886  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8887 
8888  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8889  {
8890  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8891  SCIPconsGetName(cons), minfeasibility);
8892 
8893  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8894  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8895  if ( *cutoff )
8896  return SCIP_OKAY;
8897  (*separated) = TRUE;
8898  }
8899 
8900  minfeasibility = SCIPinfinity(scip);
8901  row = NULL;
8902 
8903  /* check each row of small covers that is not contained in LP */
8904  for( r = 0; r < consdata->nbcoverrows; ++r )
8905  {
8906  if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8907  {
8908  SCIP_Real feasibility;
8909 
8910  assert(consdata->bcoverrows[r] != NULL);
8911  if( sol != NULL )
8912  feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8913  else
8914  feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8915 
8916  if( minfeasibility > feasibility )
8917  {
8918  minfeasibility = feasibility;
8919  row = consdata->bcoverrows[r];
8920  }
8921  }
8922  }
8923 
8924  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8925 
8926  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8927  {
8928  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8929  SCIPconsGetName(cons), minfeasibility);
8930 
8931  assert(row != NULL);
8932  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8933  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8934  if ( *cutoff )
8935  return SCIP_OKAY;
8936  (*separated) = TRUE;
8937  }
8938 
8939  return SCIP_OKAY;
8940 }
8941 
8942 /** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
8943 static
8945  SCIP* scip, /**< SCIP data structure */
8946  SCIP_CONS* cons, /**< constraint to be checked */
8947  int* startindices, /**< permutation with rspect to the start times */
8948  int curtime, /**< current point in time */
8949  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8950  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8951  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
8952  SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
8953  )
8954 {
8955  SCIP_CONSDATA* consdata;
8956  char name[SCIP_MAXSTRLEN];
8957  int lhs; /* left hand side of constraint */
8958 
8959  SCIP_VAR** activevars;
8960  SCIP_ROW* row;
8961 
8962  int v;
8963 
8964  assert(nstarted > nfinished);
8965 
8966  consdata = SCIPconsGetData(cons);
8967  assert(consdata != NULL);
8968  assert(consdata->nvars > 0);
8969 
8970  SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
8971 
8972  SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
8973 
8974  if( lower )
8975  {
8976  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
8977 
8978  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, (SCIP_Real) lhs, SCIPinfinity(scip),
8979  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8980  }
8981  else
8982  {
8983  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
8984  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) lhs,
8985  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8986  }
8987 
8988  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8989 
8990  for( v = 0; v < nstarted - nfinished; ++v )
8991  {
8992  SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
8993  }
8994 
8995  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8996  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8997 
8998  SCIP_CALL( SCIPaddRow(scip, row, TRUE, cutoff) );
8999 
9000  SCIP_CALL( SCIPreleaseRow(scip, &row) );
9001 
9002  /* free buffers */
9003  SCIPfreeBufferArrayNull(scip, &activevars);
9004 
9005  return SCIP_OKAY;
9006 }
9007 
9008 /** checks constraint for violation, and adds it as a cut if possible */
9009 static
9011  SCIP* scip, /**< SCIP data structure */
9012  SCIP_CONS* cons, /**< cumulative constraint to be separated */
9013  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
9014  SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
9015  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
9016  SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9017  )
9018 {
9019  SCIP_CONSDATA* consdata;
9020 
9021  int* starttimes; /* stores when each job is starting */
9022  int* endtimes; /* stores when each job ends */
9023  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
9024  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
9025 
9026  int nvars; /* number of activities for this constraint */
9027  int freecapacity; /* remaining capacity */
9028  int curtime; /* point in time which we are just checking */
9029  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
9030 
9031  int hmin;
9032  int hmax;
9033  int j;
9034 
9035  assert(scip != NULL);
9036  assert(cons != NULL);
9037 
9038  consdata = SCIPconsGetData(cons);
9039  assert(consdata != NULL);
9040 
9041  nvars = consdata->nvars;
9042 
9043  /* if no activities are associated with this cumulative then this constraint is redundant */
9044  if( nvars <= 1 )
9045  return SCIP_OKAY;
9046 
9047  assert(consdata->vars != NULL);
9048 
9049  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
9050  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
9051  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9052  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9053 
9054  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9055  SCIPconsGetName(cons), nvars);
9056 
9057  /* create event point arrays */
9058  createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9059 
9060  /* now nvars might be smaller than before! */
9061 
9062  endindex = 0;
9063  freecapacity = consdata->capacity;
9064  hmin = consdata->hmin;
9065  hmax = consdata->hmax;
9066 
9067  /* check each startpoint of a job whether the capacity is kept or not */
9068  for( j = 0; j < nvars && !(*cutoff); ++j )
9069  {
9070  curtime = starttimes[j];
9071 
9072  if( curtime >= hmax )
9073  break;
9074 
9075  /* remove the capacity requirements for all job which start at the curtime */
9076  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9077 
9078  /* add the capacity requirments for all job which end at the curtime */
9079  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9080 
9081  assert(freecapacity <= consdata->capacity);
9082  assert(endindex <= nvars);
9083 
9084  /* endindex - points to the next job which will finish */
9085  /* j - points to the last job that has been released */
9086 
9087  /* if free capacity is smaller than zero, then add rows to the LP */
9088  if( freecapacity < 0 && curtime >= hmin)
9089  {
9090  /* create capacity restriction row for current event point */
9091  SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower, cutoff) );
9092  *separated = TRUE;
9093  }
9094  } /*lint --e{850}*/
9095 
9096  /* free all buffer arrays */
9097  SCIPfreeBufferArray(scip, &endindices);
9098  SCIPfreeBufferArray(scip, &startindices);
9099  SCIPfreeBufferArray(scip, &endtimes);
9100  SCIPfreeBufferArray(scip, &starttimes);
9101 
9102  return SCIP_OKAY;
9103 }
9104 
9105 /**@} */
9106 
9107 
9108 /**@name Presolving
9109  *
9110  * @{
9111  */
9112 
9113 #ifndef NDEBUG
9114 /** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9115  * correct
9116  */
9117 static
9119  SCIP* scip, /**< SCIP data structure */
9120  SCIP_CONS* cons /**< constraint to be checked */
9121  )
9122 {
9123  SCIP_CONSDATA* consdata;
9124  int capacity;
9125  int nvars;
9126  int j;
9127 
9128  assert(scip != NULL);
9129  assert(cons != NULL);
9130 
9131  consdata = SCIPconsGetData(cons);
9132  assert(consdata != NULL);
9133 
9134  nvars = consdata->nvars;
9135 
9136  /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9137  if( nvars <= 1 )
9138  return TRUE;
9139 
9140  assert(consdata->vars != NULL);
9141  capacity = consdata->capacity;
9142 
9143  /* check each activity: if demand is larger than capacity the problem is infeasible */
9144  for ( j = 0; j < nvars; ++j )
9145  {
9146  if( consdata->demands[j] > capacity )
9147  return FALSE;
9148  }
9149 
9150  return TRUE;
9151 }
9152 #endif
9153 
9154 /** delete constraint if it consists of at most one job
9155  *
9156  * @todo this method needs to be adjusted w.r.t. effective horizon
9157  */
9158 static
9160  SCIP* scip, /**< SCIP data structure */
9161  SCIP_CONS* cons, /**< constraint to propagate */
9162  int* ndelconss, /**< pointer to store the number of deleted constraints */
9163  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9164  )
9165 {
9166  SCIP_CONSDATA* consdata;
9167 
9168  assert(scip != NULL);
9169  assert(cons != NULL);
9170 
9171  consdata = SCIPconsGetData(cons);
9172  assert(consdata != NULL);
9173 
9174  if( consdata->nvars == 0 )
9175  {
9176  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9177 
9178  SCIP_CALL( SCIPdelCons(scip, cons) );
9179  (*ndelconss)++;
9180  }
9181  else if( consdata->nvars == 1 )
9182  {
9183  if( consdata->demands[0] > consdata->capacity )
9184  (*cutoff) = TRUE;
9185  else
9186  {
9187  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9188 
9189  SCIP_CALL( SCIPdelCons(scip, cons) );
9190  (*ndelconss)++;
9191  }
9192  }
9193 
9194  return SCIP_OKAY;
9195 }
9196 
9197 /** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9198  * this is done in the SCIP_DECL_CONSINITPRE() callback
9199  */
9200 static
9202  SCIP* scip, /**< SCIP data structure */
9203  SCIP_CONS* cons /**< constraint to propagate */
9204  )
9205 {
9206  SCIP_CONSDATA* consdata;
9207  SCIP_VAR* var;
9208  int demand;
9209  int duration;
9210  int hmin;
9211  int hmax;
9212  int est;
9213  int lct;
9214  int j;
9215 
9216  assert(scip != NULL);
9217  assert(cons != NULL);
9218 
9219  consdata = SCIPconsGetData(cons);
9220  assert(consdata != NULL);
9221 
9222  hmin = consdata->hmin;
9223  hmax = consdata->hmax;
9224 
9225  SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9226  SCIPconsGetName(cons), hmin, hmax);
9227 
9228  for( j = consdata->nvars-1; j >= 0; --j )
9229  {
9230  var = consdata->vars[j];
9231  demand = consdata->demands[j];
9232  duration = consdata->durations[j];
9233 
9234  /* earliest completion time (ect) and latest start time (lst) */
9235  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9236  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9237 
9238  if( demand == 0 || duration == 0 )
9239  {
9240  /* jobs with zero demand or zero duration can be removed */
9241  SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
9242  SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9243 
9244  /* remove variable form constraint */
9245  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9246  }
9247  else if( est >= hmax || lct <= hmin )
9248  {
9249  SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
9250  SCIPvarGetName(var), est, lct - duration, duration);
9251 
9252  /* delete variable at the given position */
9253  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9254 
9255  /* for the statistic we count the number of jobs which are irrelevant */
9256  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9257  }
9258  }
9259 
9260  return SCIP_OKAY;
9261 }
9262 
9263 /** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9264 static
9266  SCIP* scip, /**< SCIP data structure */
9267  SCIP_CONSDATA* consdata, /**< constraint data */
9268  int pos, /**< position of job in the consdata */
9269  int* nchgbds, /**< pointer to store the number of changed bounds */
9270  int* naddconss, /**< pointer to store the number of added constraints */
9271  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9272  )
9273 {
9274  SCIP_VAR* var;
9275  SCIP_Bool tightened;
9276  int duration;
9277  int ect;
9278  int lst;
9279 
9280  assert(scip != NULL);
9281 
9282  /* zero energy jobs should be removed already */
9283  assert(consdata->durations[pos] > 0);
9284  assert(consdata->demands[pos] > 0);
9285 
9286  var = consdata->vars[pos];
9287  assert(var != NULL);
9288  duration = consdata->durations[pos];
9289 
9290  /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9291  SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9292  SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9293 
9294  /* earliest completion time (ect) and latest start time (lst) */
9295  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9296  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9297 
9298  /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9299  if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9300  return SCIP_OKAY;
9301 
9302  if( ect > consdata->hmin && lst < consdata->hmax )
9303  {
9304  /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9305  *cutoff = TRUE;
9306  }
9307  else if( lst < consdata->hmax )
9308  {
9309  /* move the latest start time of this job in such a way that it finishes before or at hmin */
9310  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9311  assert(tightened);
9312  assert(!(*cutoff));
9313  (*nchgbds)++;
9314  }
9315  else if( ect > consdata->hmin )
9316  {
9317  /* move the earliest start time of this job in such a way that it starts after or at hmax */
9318  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9319  assert(tightened);
9320  assert(!(*cutoff));
9321  (*nchgbds)++;
9322  }
9323  else
9324  {
9325  /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9326  * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9327  *
9328  * (var <= hmin - duration) /\ (var >= hmax)
9329  */
9330  SCIP_CONS* cons;
9331 
9332  SCIP_VAR* vartuple[2];
9333  SCIP_BOUNDTYPE boundtypetuple[2];
9334  SCIP_Real boundtuple[2];
9335 
9336  char name[SCIP_MAXSTRLEN];
9337  int leftbound;
9338  int rightbound;
9339 
9340  leftbound = consdata->hmin - duration;
9341  rightbound = consdata->hmax;
9342 
9343  /* allocate temporary memory for arrays */
9344  vartuple[0] = var;
9345  vartuple[1] = var;
9346  boundtuple[0] = (SCIP_Real)leftbound;
9347  boundtuple[1] = (SCIP_Real)rightbound;
9348  boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9349  boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9350 
9351  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9352  SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9353 
9354  /* create and add bounddisjunction constraint */
9355  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9356  TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9357 
9358  SCIPdebugPrintCons(scip, cons, NULL);
9359 
9360  /* add and release the new constraint */
9361  SCIP_CALL( SCIPaddCons(scip, cons) );
9362  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9363  (*naddconss)++;
9364  }
9365 
9366  return SCIP_OKAY;
9367 }
9368 
9369 /** try to removed over sizeed jobs (the demand is larger than the capacity) */
9370 static
9372  SCIP* scip, /**< SCIP data structure */
9373  SCIP_CONS* cons, /**< constraint */
9374  int* nchgbds, /**< pointer to store the number of changed bounds */
9375  int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9376  int* naddconss, /**< pointer to store the number of added constraints */
9377  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9378  )
9379 {
9380  SCIP_CONSDATA* consdata;
9381  int capacity;
9382  int j;
9383 
9384  consdata = SCIPconsGetData(cons);
9385  assert(consdata != NULL);
9386 
9387  /* if a cutoff was already detected just return */
9388  if( *cutoff )
9389  return SCIP_OKAY;
9390 
9391  capacity = consdata->capacity;
9392 
9393  for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9394  {
9395  if( consdata->demands[j] > capacity )
9396  {
9397  SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9398 
9399  /* remove variable form constraint */
9400  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9401  (*nchgcoefs)++;
9402  }
9403  }
9404 
9405  SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9406 
9407  return SCIP_OKAY;
9408 }
9409 
9410 /** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9411 static
9413  SCIP* scip, /**< SCIP data structure */
9414  SCIP_VAR* var, /**< integer variable to fix */
9415  SCIP_Bool uplock, /**< has thet start time variable a up lock */
9416  int* nfixedvars /**< pointer to store the number fixed variables */
9417  )
9418 {
9419  SCIP_Bool infeasible;
9420  SCIP_Bool tightened;
9421  SCIP_Bool roundable;
9422 
9423  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9424  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9425  */
9426  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9427  return SCIP_OKAY;
9428 
9429  /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9430  * handler is the only one locking that variable up
9431  */
9432  assert(uplock == TRUE || uplock == FALSE);
9433  assert((int)TRUE == 1);
9434  assert((int)FALSE == 0);
9435 
9436  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)(uplock) )
9437  return SCIP_OKAY;
9438 
9439  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9440 
9441  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9442  * (the transformed problem is always a minimization problem)
9443  */
9444  if( !roundable )
9445  return SCIP_OKAY;
9446 
9447  SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9449 
9450  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9451  assert(!infeasible);
9452 
9453  if( tightened )
9454  {
9455  SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9456  (*nfixedvars)++;
9457  }
9458 
9459  return SCIP_OKAY;
9460 }
9461 
9462 /** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9463 static
9465  SCIP* scip, /**< SCIP data structure */
9466  SCIP_VAR* var, /**< integer variable to fix */
9467  SCIP_Bool downlock, /**< has the variable a down lock */
9468  int* nfixedvars /**< pointer to store the number fixed variables */
9469  )
9470 {
9471  SCIP_Bool infeasible;
9472  SCIP_Bool tightened;
9473  SCIP_Bool roundable;
9474 
9475  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9476  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9477  */
9478  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9479  return SCIP_OKAY;
9480 
9481  /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9482  * handler is the only one locking that variable down
9483  */
9484  assert(downlock == TRUE || downlock == FALSE);
9485  assert((int)TRUE == 1);
9486  assert((int)FALSE == 0);
9487 
9488  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)(downlock) )
9489  return SCIP_OKAY;
9490 
9491  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9492 
9493  /* is it possible, to round variable down w.r.t. objective function? */
9494  if( !roundable )
9495  return SCIP_OKAY;
9496 
9497  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9498  assert(!infeasible);
9499 
9500  if( tightened )
9501  {
9502  SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9503  (*nfixedvars)++;
9504  }
9505 
9506  return SCIP_OKAY;
9507 }
9508 
9509 /** normalize cumulative condition */
9510 static
9512  SCIP* scip, /**< SCIP data structure */
9513  int nvars, /**< number of start time variables (activities) */
9514  int* demands, /**< array of demands */
9515  int* capacity, /**< pointer to store the changed cumulative capacity */
9516  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9517  int* nchgsides /**< pointer to count number of side changes */
9518  )
9519 { /*lint --e{715}*/
9520  SCIP_Longint gcd;
9521  int mindemand1;
9522  int mindemand2;
9523  int v;
9524 
9525  if( *capacity == 1 || nvars <= 1 )
9526  return;
9527 
9528  assert(demands[nvars-1] <= *capacity);
9529  assert(demands[nvars-2] <= *capacity);
9530 
9531  gcd = (SCIP_Longint)demands[nvars-1];
9532  mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9533  mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9534 
9535  for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9536  {
9537  assert(mindemand1 <= mindemand2);
9538  assert(demands[v] <= *capacity);
9539 
9540  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9541 
9542  if( mindemand1 > demands[v] )
9543  {
9544  mindemand2 = mindemand1;
9545  mindemand1 = demands[v];
9546  }
9547  else if( mindemand2 > demands[v] )
9548  mindemand2 = demands[v];
9549  }
9550 
9551  if( mindemand1 + mindemand2 > *capacity )
9552  {
9553  SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9554 
9555  for( v = 0; v < nvars; ++v )
9556  demands[v] = 1;
9557 
9558  (*capacity) = 1;
9559 
9560  (*nchgcoefs) += nvars;
9561  (*nchgsides)++;
9562  }
9563  else if( gcd >= 2 )
9564  {
9565  SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9566 
9567  for( v = 0; v < nvars; ++v )
9568  demands[v] /= (int) gcd;
9569 
9570  (*capacity) /= (int) gcd;
9571 
9572  (*nchgcoefs) += nvars;
9573  (*nchgsides)++;
9574  }
9575 }
9576 
9577 /** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9578  * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9579  * capacity since in that case none of the jobs can run in parallel
9580  */
9581 static
9582 void normalizeDemands(
9583  SCIP* scip, /**< SCIP data structure */
9584  SCIP_CONS* cons, /**< cumulative constraint */
9585  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9586  int* nchgsides /**< pointer to count number of side changes */
9587  )
9588 {
9589  SCIP_CONSDATA* consdata;
9590  int capacity;
9591 
9592  assert(nchgcoefs != NULL);
9593  assert(nchgsides != NULL);
9594  assert(!SCIPconsIsModifiable(cons));
9595 
9596  consdata = SCIPconsGetData(cons);
9597  assert(consdata != NULL);
9598 
9599  if( consdata->normalized )
9600  return;
9601 
9602  capacity = consdata->capacity;
9603 
9604  /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9605 
9606  normalizeCumulativeCondition(scip, consdata->nvars, consdata->demands, &consdata->capacity, nchgcoefs, nchgsides);
9607 
9608  consdata->normalized = TRUE;
9609 
9610  if( capacity > consdata->capacity )
9611  consdata->varbounds = FALSE;
9612 }
9613 
9614 /** computes for the given cumulative condition the effective horizon */
9615 static
9617  SCIP* scip, /**< SCIP data structure */
9618  int nvars, /**< number of variables (jobs) */
9619  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9620  int* durations, /**< array containing corresponding durations */
9621  int* demands, /**< array containing corresponding demands */
9622  int capacity, /**< available cumulative capacity */
9623  int* hmin, /**< pointer to store the left bound of the effective horizon */
9624  int* hmax, /**< pointer to store the right bound of the effective horizon */
9625  int* split /**< point were the cumulative condition can be split */
9626  )
9627 {
9628  SCIP_PROFILE* profile;
9629 
9630  /* create empty resource profile with infinity resource capacity */
9631  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9632 
9633  /* create worst case resource profile */
9634  SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
9635 
9636  /* print resource profile in if SCIP_DEBUG is defined */
9637  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
9638 
9639  /* computes the first time point where the resource capacity can be violated */
9640  (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9641 
9642  /* computes the first time point where the resource capacity is satisfied for sure */
9643  (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9644 
9645  (*split) = (*hmax);
9646 
9647  if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9648  {
9649  int* timepoints;
9650  int* loads;
9651  int ntimepoints;
9652  int t;
9653 
9654  /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9655  * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9656  * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9657  * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9658  * explain the certain "old" bound changes
9659  */
9660 
9661  /* search for time points */
9662  ntimepoints = SCIPprofileGetNTimepoints(profile);
9663  timepoints = SCIPprofileGetTimepoints(profile);
9664  loads = SCIPprofileGetLoads(profile);
9665 
9666  /* 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 */
9667  for( t = 0; t < ntimepoints; ++t )
9668  {
9669  /* ignore all time points before the effective horizon */
9670  if( timepoints[t] <= *hmin )
9671  continue;
9672 
9673  /* ignore all time points after the effective horizon */
9674  if( timepoints[t] >= *hmax )
9675  break;
9676 
9677  /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9678  * can split the cumulative constraint into two cumulative constraints
9679  */
9680  if( loads[t] <= capacity )
9681  {
9682  (*split) = timepoints[t];
9683  break;
9684  }
9685  }
9686  }
9687 
9688  /* free worst case profile */
9689  SCIPprofileFree(&profile);
9690 
9691  return SCIP_OKAY;
9692 }
9693 
9694 /** creates and adds a cumulative constraint */
9695 static
9697  SCIP* scip, /**< SCIP data structure */
9698  const char* name, /**< name of constraint */
9699  int nvars, /**< number of variables (jobs) */
9700  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9701  int* durations, /**< array containing corresponding durations */
9702  int* demands, /**< array containing corresponding demands */
9703  int capacity, /**< available cumulative capacity */
9704  int hmin, /**< left bound of time axis to be considered (including hmin) */
9705  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9706  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9707  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9708  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9709  * Usually set to TRUE. */
9710  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9711  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9712  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9713  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9714  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9715  * Usually set to TRUE. */
9716  SCIP_Bool local, /**< is constraint only valid locally?
9717  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9718  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9719  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9720  * adds coefficients to this constraint. */
9721  SCIP_Bool dynamic, /**< is constraint subject to aging?
9722  * Usually set to FALSE. Set to TRUE for own cuts which
9723  * are seperated as constraints. */
9724  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9725  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9726  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9727  * if it may be moved to a more global node?
9728  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9729  )
9730 {
9731  SCIP_CONS* cons;
9732 
9733  /* creates cumulative constraint and adds it to problem */
9734  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9735  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9736 
9737  /* adjust the effective time horizon of the new constraint */
9738  SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9739  SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9740 
9741  /* add and release new cumulative constraint */
9742  SCIP_CALL( SCIPaddCons(scip, cons) );
9743  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9744 
9745  return SCIP_OKAY;
9746 }
9747 
9748 /** computes the effective horizon and checks if the constraint can be decompsed */
9749 static
9751  SCIP* scip, /**< SCIP data structure */
9752  SCIP_CONS* cons, /**< cumulative constraint */
9753  int* ndelconss, /**< pointer to store the number of deleted constraints */
9754  int* naddconss, /**< pointer to store the number of added constraints */
9755  int* nchgsides /**< pointer to store the number of changed sides */
9756  )
9757 {
9758  SCIP_CONSDATA* consdata;
9759  int hmin;
9760  int hmax;
9761  int split;
9762 
9763  consdata = SCIPconsGetData(cons);
9764  assert(consdata != NULL);
9765 
9766  if( consdata->nvars <= 1 )
9767  return SCIP_OKAY;
9768 
9769  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9770  consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9771 
9772  /* check if this time point improves the effective horizon */
9773  if( consdata->hmin < hmin )
9774  {
9775  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9776 
9777  consdata->hmin = hmin;
9778  (*nchgsides)++;
9779  }
9780 
9781  /* check if this time point improves the effective horizon */
9782  if( consdata->hmax > hmax )
9783  {
9784  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9785  consdata->hmax = hmax;
9786  (*nchgsides)++;
9787  }
9788 
9789  /* check if the constraint is redundant */
9790  if( consdata->hmax <= consdata->hmin )
9791  {
9792  SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9793  SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9794 
9795  SCIP_CALL( SCIPdelCons(scip, cons) );
9796  (*ndelconss)++;
9797  }
9798  else if( consdata->hmin < split && split < consdata->hmax )
9799  {
9800  char name[SCIP_MAXSTRLEN];
9801  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9802 
9803  SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9804  SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9805 
9806  assert(split < consdata->hmax);
9807 
9808  /* creates cumulative constraint and adds it to problem */
9809  SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9810  consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9813 
9814  /* adjust the effective time horizon of the constraint */
9815  consdata->hmax = split;
9816 
9817  assert(consdata->hmin < consdata->hmax);
9818 
9819  /* for the statistic we count the number of time we decompose a cumulative constraint */
9821  (*naddconss)++;
9822  }
9823 
9824  return SCIP_OKAY;
9825 }
9826 
9827 
9828 /** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9829  *
9830  * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9831  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9832  *
9833  * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9834  * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9835  * down-lock of the corresponding start time variable can be removed.
9836  *
9837  * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9838  * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9839  * negative, than the job can be dual fixed to its earlier start time (est).
9840  *
9841  * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9842  * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9843  * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9844  *
9845  * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9846  * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9847  * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9848  * form variable domain is dual feasible.
9849  *
9850  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9851  * the cumulative condition; The deletion has to be done later.
9852  */
9853 static
9855  SCIP* scip, /**< SCIP data structure */
9856  int nvars, /**< number of start time variables (activities) */
9857  SCIP_VAR** vars, /**< array of start time variables */
9858  int* durations, /**< array of durations */
9859  int hmin, /**< left bound of time axis to be considered (including hmin) */
9860  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9861  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9862  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9863  SCIP_CONS* cons, /**< underlying constraint, or NULL */
9864  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9865  int* nfixedvars, /**< pointer to store the number of fixed variables */
9866  int* nchgsides, /**< pointer to store the number of changed sides */
9867  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9868  )
9869 {
9870  SCIP_Real* downimpllbs;
9871  SCIP_Real* downimplubs;
9872  SCIP_Real* downproplbs;
9873  SCIP_Real* downpropubs;
9874  SCIP_Real* upimpllbs;
9875  SCIP_Real* upimplubs;
9876  SCIP_Real* upproplbs;
9877  SCIP_Real* uppropubs;
9878 
9879  int firstminect;
9880  int secondminect;
9881  int v;
9882 
9883  /* get temporary memory for storing probing results needed for step (4) and (5) */
9884  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9885  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9886  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9887  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9888  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9889  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9890  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9891  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9892 
9893  assert(scip != NULL);
9894  assert(nvars > 1);
9895  assert(cons != NULL);
9896 
9897  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9898 
9899  firstminect = INT_MAX;
9900  secondminect = INT_MAX;
9901 
9902  /* compute the two smallest earlier completion times; which are needed for step (5) */
9903  for( v = 0; v < nvars; ++v )
9904  {
9905  int ect;
9906 
9907  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9908 
9909  if( ect < firstminect )
9910  {
9911  secondminect = firstminect;
9912  firstminect = ect;
9913  }
9914  else if( ect < secondminect )
9915  secondminect = ect;
9916  }
9917 
9918  /* loop over all jobs and check if one of the 5 reductions can be applied */
9919  for( v = 0; v < nvars; ++v )
9920  {
9921  SCIP_VAR* var;
9922  int duration;
9923 
9924  int alternativelb;
9925  int minect;
9926  int est;
9927  int ect;
9928  int lst;
9929  int lct;
9930 
9931  var = vars[v];
9932  assert(var != NULL);
9933 
9934  duration = durations[v];
9935  assert(duration > 0);
9936 
9937  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
9938  * time (lct)
9939  */
9940  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9941  ect = est + duration;
9942  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9943  lct = lst + duration;
9944 
9945  /* compute the earliest completion time of all remaining jobs */
9946  if( ect == firstminect )
9947  minect = secondminect;
9948  else
9949  minect = firstminect;
9950 
9951  /* compute potential alternative lower bound (step (4) and (5)) */
9952  alternativelb = MAX(hmin+1, minect);
9953  alternativelb = MIN(alternativelb, hmax);
9954 
9955  if( lct <= hmin )
9956  {
9957  /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
9958  * cumulative condition
9959  */
9960  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
9961  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
9962 
9963  /* mark variable to be irrelevant */
9964  irrelevants[v] = TRUE;
9965 
9966  /* for the statistic we count the number of jobs which are irrelevant */
9967  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9968  }
9969  else if( lst <= hmin && SCIPconsIsChecked(cons) )
9970  {
9971  /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
9972  * so the down lock can be omitted
9973  */
9974 
9975  assert(downlocks != NULL);
9976  assert(uplocks != NULL);
9977 
9978  if( !uplocks[v] )
9979  {
9980  /* the variables has no up lock and we can also remove the down lock;
9981  * => lst <= hmin and ect >= hmax
9982  * => remove job and reduce capacity by the demand of that job
9983  *
9984  * We mark the job to be deletable. The removement together with the capacity reducion is done later
9985  */
9986 
9987  SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
9988  SCIPvarGetName(var), ect - duration, lst, duration);
9989 
9990  /* mark variable to be irrelevant */
9991  irrelevants[v] = TRUE;
9992 
9993  /* for the statistic we count the number of jobs which always run during the effective horizon */
9995  }
9996 
9997  if( downlocks[v] )
9998  {
9999  SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
10000  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10001 
10002  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
10003  downlocks[v] = FALSE;
10004  (*nchgsides)++;
10005 
10006  /* for the statistic we count the number of removed locks */
10008  }
10009  }
10010  else if( ect <= hmin )
10011  {
10012  /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
10013  * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
10014  * removed form the cumulative condition after it was fixed to its earliest start time
10015  */
10016 
10017  /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
10018  * bound;
10019  */
10020  if( downlocks != NULL && SCIPconsIsChecked(cons) )
10021  {
10022  /* fix integer start time variable if possible to it lower bound */
10023  SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
10024  }
10025 
10026  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10027  {
10028  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
10029  SCIPvarGetName(var), ect - duration, lst, duration);
10030 
10031  /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
10032  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
10033 
10034  /* mark variable to be irrelevant */
10035  irrelevants[v] = TRUE;
10036 
10037  /* for the statistic we count the number of jobs which are dual fixed */
10039  }
10040  }
10041  else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10042  {
10043  assert(downlocks != NULL);
10044 
10045  /* check step (4) and (5) */
10046 
10047  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10048  * is in favor of rounding the variable down
10049  */
10050  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
10051  {
10052  SCIP_Bool roundable;
10053 
10054  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10055 
10056  if( roundable )
10057  {
10058  if( alternativelb > lst )
10059  {
10060  SCIP_Bool infeasible;
10061  SCIP_Bool fixed;
10062 
10063  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10064  assert(!infeasible);
10065  assert(fixed);
10066 
10067  (*nfixedvars)++;
10068 
10069  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10070  * constraints
10071  */
10073  }
10074  else
10075  {
10076  SCIP_Bool success;
10077 
10078  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10079  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10080  * infeasible we can apply the dual reduction; otherwise we do nothing
10081  */
10082  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10083  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10084  nfixedvars, &success, cutoff) );
10085 
10086  if( success )
10087  {
10089  }
10090  }
10091  }
10092  }
10093  }
10094 
10095  SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10096  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10097  }
10098 
10099  /* free temporary memory */
10100  SCIPfreeBufferArray(scip, &uppropubs);
10101  SCIPfreeBufferArray(scip, &upproplbs);
10102  SCIPfreeBufferArray(scip, &upimplubs);
10103  SCIPfreeBufferArray(scip, &upimpllbs);
10104  SCIPfreeBufferArray(scip, &downpropubs);
10105  SCIPfreeBufferArray(scip, &downproplbs);
10106  SCIPfreeBufferArray(scip, &downimplubs);
10107  SCIPfreeBufferArray(scip, &downimpllbs);
10108 
10109  return SCIP_OKAY;
10110 }
10111 
10112 /** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10113  *
10114  * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10115  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10116  *
10117  * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10118  * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10119  * up-lock of the corresponding start time variable can be removed.
10120  *
10121  * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10122  * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10123  * positive, than the job can be dual fixed to its latest start time (lst).
10124  *
10125  * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10126  * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10127  * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10128  * of the corresponding job).
10129 
10130  * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10131  * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10132  * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10133  * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10134  *
10135  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10136  * the cumulative condition; The deletion has to be done later.
10137  */
10138 static
10140  SCIP* scip, /**< SCIP data structure */
10141  int nvars, /**< number of start time variables (activities) */
10142  SCIP_VAR** vars, /**< array of start time variables */
10143  int* durations, /**< array of durations */
10144  int hmin, /**< left bound of time axis to be considered (including hmin) */
10145  int hmax, /**< right bound of time axis to be considered (not including hmax) */
10146  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10147  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10148  SCIP_CONS* cons, /**< underlying constraint, or NULL */
10149  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10150  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10151  int* nchgsides, /**< pointer to store the number of changed sides */
10152  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10153  )
10154 {
10155  SCIP_Real* downimpllbs;
10156  SCIP_Real* downimplubs;
10157  SCIP_Real* downproplbs;
10158  SCIP_Real* downpropubs;
10159  SCIP_Real* upimpllbs;
10160  SCIP_Real* upimplubs;
10161  SCIP_Real* upproplbs;
10162  SCIP_Real* uppropubs;
10163 
10164  int firstmaxlst;
10165  int secondmaxlst;
10166  int v;
10167 
10168  /* get temporary memory for storing probing results needed for step (4) and (5) */
10169  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10170  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10171  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10172  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10173  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10174  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10175  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10176  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10177 
10178  assert(scip != NULL);
10179  assert(nvars > 1);
10180  assert(cons != NULL);
10181 
10182  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10183 
10184  firstmaxlst = INT_MIN;
10185  secondmaxlst = INT_MIN;
10186 
10187  /* compute the two largest latest start times; which are needed for step (5) */
10188  for( v = 0; v < nvars; ++v )
10189  {
10190  int lst;
10191 
10192  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(vars[v]));
10193 
10194  if( lst > firstmaxlst )
10195  {
10196  secondmaxlst = firstmaxlst;
10197  firstmaxlst = lst;
10198  }
10199  else if( lst > secondmaxlst )
10200  secondmaxlst = lst;
10201  }
10202 
10203  /* loop over all jobs and check if one of the 5 reductions can be applied */
10204  for( v = 0; v < nvars; ++v )
10205  {
10206  SCIP_VAR* var;
10207  int duration;
10208 
10209  int alternativeub;
10210  int maxlst;
10211  int est;
10212  int ect;
10213  int lst;
10214 
10215  var = vars[v];
10216  assert(var != NULL);
10217 
10218  duration = durations[v];
10219  assert(duration > 0);
10220 
10221  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10222  * time (lct)
10223  */
10224  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10225  ect = est + duration;
10226  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10227 
10228  /* compute the latest start time of all remaining jobs */
10229  if( lst == firstmaxlst )
10230  maxlst = secondmaxlst;
10231  else
10232  maxlst = firstmaxlst;
10233 
10234  /* compute potential alternative upper bound (step (4) and (5)) */
10235  alternativeub = MIN(hmax - 1, maxlst) - duration;
10236  alternativeub = MAX(alternativeub, hmin);
10237 
10238  if( est >= hmax )
10239  {
10240  /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10241  * cumulative condition
10242  */
10243  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10244  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10245 
10246  /* mark variable to be irrelevant */
10247  irrelevants[v] = TRUE;
10248 
10249  /* for the statistic we count the number of jobs which are irrelevant */
10250  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10251  }
10252  else if( ect >= hmax && SCIPconsIsChecked(cons) )
10253  {
10254  assert(downlocks != NULL);
10255  assert(uplocks != NULL);
10256 
10257  /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10258  * so the up lock can be omitted
10259  */
10260 
10261  if( !downlocks[v] )
10262  {
10263  /* the variables has no down lock and we can also remove the up lock;
10264  * => lst <= hmin and ect >= hmax
10265  * => remove job and reduce capacity by the demand of that job
10266  */
10267  SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10268  SCIPvarGetName(var), est, lst, duration);
10269 
10270  /* mark variable to be irrelevant */
10271  irrelevants[v] = TRUE;
10272 
10273  /* for the statistic we count the number of jobs which always run during the effective horizon */
10275  }
10276 
10277  if( uplocks[v] )
10278  {
10279  SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10280  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10281 
10282  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10283  uplocks[v] = FALSE;
10284  (*nchgsides)++;
10285 
10286  /* for the statistic we count the number of removed locks */
10288  }
10289  }
10290  else if( lst >= hmax )
10291  {
10292  /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10293  * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10294  * removed form the cumulative condition after it was fixed to its latest start time
10295  */
10296 
10297  /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10298  * bound
10299  */
10300  if( uplocks != NULL && SCIPconsIsChecked(cons) )
10301  {
10302  /* fix integer start time variable if possible to its upper bound */
10303  SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10304  }
10305 
10306  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10307  {
10308  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10309  SCIPvarGetName(var), est, lst, duration);
10310 
10311  /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10312  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10313 
10314  /* mark variable to be irrelevant */
10315  irrelevants[v] = TRUE;
10316 
10317  /* for the statistic we count the number of jobs which are dual fixed */
10319  }
10320  }
10321  else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10322  {
10323  assert(uplocks != NULL);
10324 
10325  /* check step (4) and (5) */
10326 
10327  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10328  * is in favor of rounding the variable down
10329  */
10330  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
10331  {
10332  SCIP_Bool roundable;
10333 
10334  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10335 
10336  if( roundable )
10337  {
10338  if( alternativeub < est )
10339  {
10340  SCIP_Bool infeasible;
10341  SCIP_Bool fixed;
10342 
10343  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10344  assert(!infeasible);
10345  assert(fixed);
10346 
10347  (*nfixedvars)++;
10348 
10349  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10350  * constraints
10351  */
10353  }
10354  else
10355  {
10356  SCIP_Bool success;
10357 
10358  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10359  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10360  * in infeasible we can apply the dual reduction; otherwise we do nothing
10361  */
10362  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10363  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10364  nfixedvars, &success, cutoff) );
10365 
10366  if( success )
10367  {
10369  }
10370  }
10371  }
10372  }
10373  }
10374  }
10375 
10376  /* free temporary memory */
10377  SCIPfreeBufferArray(scip, &uppropubs);
10378  SCIPfreeBufferArray(scip, &upproplbs);
10379  SCIPfreeBufferArray(scip, &upimplubs);
10380  SCIPfreeBufferArray(scip, &upimpllbs);
10381  SCIPfreeBufferArray(scip, &downpropubs);
10382  SCIPfreeBufferArray(scip, &downproplbs);
10383  SCIPfreeBufferArray(scip, &downimplubs);
10384  SCIPfreeBufferArray(scip, &downimpllbs);
10385 
10386  return SCIP_OKAY;
10387 }
10388 
10389 /** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10390 static
10392  SCIP* scip, /**< SCIP data structure */
10393  SCIP_CONS* cons, /**< cumulative constraint */
10394  int* nfixedvars, /**< pointer to store the number of fixed variables */
10395  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10396  int* nchgsides, /**< pointer to store the number of changed sides */
10397  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10398  )
10399 {
10400  SCIP_CONSDATA* consdata;
10401  SCIP_Bool* irrelevants;
10402  int nvars;
10403  int v;
10404 
10405  assert(scip != NULL);
10406  assert(cons != NULL);
10407  assert(!(*cutoff));
10408 
10409  consdata = SCIPconsGetData(cons);
10410  assert(consdata != NULL);
10411 
10412  nvars = consdata->nvars;
10413 
10414  if( nvars <= 1 )
10415  return SCIP_OKAY;
10416 
10417  SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10418  BMSclearMemoryArray(irrelevants, nvars);
10419 
10420  /* presolve constraint form the earlier start time point of view */
10421  SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10422  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10423  irrelevants, nfixedvars, nchgsides, cutoff) );
10424 
10425  /* presolve constraint form the latest completion time point of view */
10426  SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10427  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10428  irrelevants, nfixedvars, nchgsides, cutoff) );
10429 
10430  /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10431  * order to ensure a correct behaviour
10432  */
10433  for( v = nvars-1; v >= 0; --v )
10434  {
10435  if( irrelevants[v] )
10436  {
10437  SCIP_VAR* var;
10438  int ect;
10439  int lst;
10440 
10441  var = consdata->vars[v];
10442  assert(var != NULL);
10443 
10444  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10445  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10446 
10447  /* check if the jobs runs completely during the effective horizon */
10448  if( lst <= consdata->hmin && ect >= consdata->hmax )
10449  {
10450  if( consdata->capacity < consdata->demands[v] )
10451  {
10452  *cutoff = TRUE;
10453  break;
10454  }
10455 
10456  consdata->capacity -= consdata->demands[v];
10457  consdata->varbounds = FALSE;
10458  }
10459 
10460  SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10461  (*nchgcoefs)++;
10462  }
10463  }
10464 
10465  SCIPfreeBufferArray(scip, &irrelevants);
10466 
10467  return SCIP_OKAY;
10468 }
10469 
10470 /** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10471 static
10472 void collectDemands(
10473  SCIP* scip, /**< SCIP data structure */
10474  SCIP_CONSDATA* consdata, /**< constraint data */
10475  int* startindices, /**< permutation with rspect to the start times */
10476  int curtime, /**< current point in time */
10477  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10478  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10479  SCIP_Longint** demands, /**< pointer to array storing the demands */
10480  int* ndemands /**< pointer to store the number of different demands */
10481  )
10482 {
10483  int startindex;
10484  int ncountedvars;
10485 
10486  assert(demands != NULL);
10487  assert(ndemands != NULL);
10488 
10489  ncountedvars = 0;
10490  startindex = nstarted - 1;
10491 
10492  *ndemands = 0;
10493 
10494  /* search for the (nstarted - nfinished) jobs which are active at curtime */
10495  while( nstarted - nfinished > ncountedvars )
10496  {
10497  SCIP_VAR* var;
10498  int endtime;
10499  int varidx;
10500 
10501  /* collect job information */
10502  varidx = startindices[startindex];
10503  assert(varidx >= 0 && varidx < consdata->nvars);
10504 
10505  var = consdata->vars[varidx];
10506  assert(var != NULL);
10507 
10508  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10509 
10510  /* check the end time of this job is larger than the curtime; in this case the job is still running */
10511  if( endtime > curtime )
10512  {
10513  if( consdata->demands[varidx] < consdata->capacity )
10514  {
10515  (*demands)[*ndemands] = consdata->demands[varidx];
10516  (*ndemands)++;
10517  }
10518  ncountedvars++;
10519  }
10520 
10521  startindex--;
10522  }
10523 }
10524 
10525 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10526  * constraint
10527  */
10528 static
10530  SCIP* scip, /**< SCIP data structure */
10531  SCIP_CONS* cons, /**< constraint to be checked */
10532  int* startindices, /**< permutation with rspect to the start times */
10533  int curtime, /**< current point in time */
10534  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10535  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10536  int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10537  )
10538 {
10539  SCIP_CONSDATA* consdata;
10540  SCIP_Longint* demands;
10541  SCIP_Real* profits;
10542  int* items;
10543  int ndemands;
10544  SCIP_Bool success;
10545  SCIP_Real solval;
10546  int j;
10547  assert(nstarted > nfinished);
10548 
10549  consdata = SCIPconsGetData(cons);
10550  assert(consdata != NULL);
10551  assert(consdata->nvars > 0);
10552  assert(consdata->capacity > 0);
10553 
10554  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10555  ndemands = 0;
10556 
10557  /* get demand array to initialize knapsack problem */
10558  collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands);
10559 
10560  /* create array for profits */
10561  SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10562  SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10563  for( j = 0; j < ndemands; ++j )
10564  {
10565  profits[j] = (SCIP_Real) demands[j];
10566  items[j] = j;/* this is only a dummy value*/
10567  }
10568 
10569  /* solve knapsack problem and get maximum capacity usage <= capacity */
10570  SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10571  items, NULL, NULL, NULL, NULL, &solval, &success) );
10572 
10573  assert(SCIPisFeasIntegral(scip, solval));
10574 
10575  /* store result */
10576  *bestcapacity = SCIPconvertRealToInt(scip, solval);
10577 
10578  SCIPfreeBufferArray(scip, &items);
10579  SCIPfreeBufferArray(scip, &profits);
10580  SCIPfreeBufferArray(scip, &demands);
10581 
10582  return SCIP_OKAY;
10583 }
10584 
10585 /** try to tighten the capacity
10586  * -- using DP for knapsack, we find the maximum possible capacity usage
10587  * -- neglects hmin and hmax, such that it is also able to check solutions globally
10588  */
10589 static
10591  SCIP* scip, /**< SCIP data structure */
10592  SCIP_CONS* cons, /**< cumulative constraint */
10593  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10594  int* nchgsides /**< pointer to store the number of changed sides */
10595  )
10596 {
10597  SCIP_CONSDATA* consdata;
10598  int* starttimes; /* stores when each job is starting */
10599  int* endtimes; /* stores when each job ends */
10600  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10601  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10602 
10603  int nvars; /* number of activities for this constraint */
10604  int freecapacity; /* remaining capacity */
10605  int curtime; /* point in time which we are just checking */
10606  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10607 
10608  int bestcapacity;
10609 
10610  int j;
10611 
10612  assert(scip != NULL);
10613  assert(cons != NULL);
10614  assert(nchgsides != NULL);
10615 
10616  consdata = SCIPconsGetData(cons);
10617  assert(consdata != NULL);
10618 
10619  nvars = consdata->nvars;
10620 
10621  /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10622  if( nvars <= 1 || consdata->capacity <= 1 )
10623  return SCIP_OKAY;
10624 
10625  assert(consdata->vars != NULL);
10626 
10627  SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10628  SCIPconsGetName(cons), consdata->capacity);
10629 
10630  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10631  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10632  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10633  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10634 
10635  /* create event point arrays */
10636  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10637  starttimes, endtimes, startindices, endindices, FALSE);
10638 
10639  bestcapacity = 1;
10640  endindex = 0;
10641  freecapacity = consdata->capacity;
10642 
10643  /* check each startpoint of a job whether the capacity is kept or not */
10644  for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10645  {
10646  curtime = starttimes[j];
10647  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10648 
10649  /* remove the capacity requirments for all job which start at the curtime */
10650  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10651 
10652  /* add the capacity requirments for all job which end at the curtime */
10653  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10654 
10655  assert(freecapacity <= consdata->capacity);
10656  assert(endindex <= nvars);
10657 
10658  /* endindex - points to the next job which will finish */
10659  /* j - points to the last job that has been released */
10660 
10661  /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10662  if( freecapacity < 0 )
10663  {
10664  int newcapacity;
10665 
10666  newcapacity = 1;
10667 
10668  /* get best possible upper bound on capacity usage */
10669  SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10670 
10671  /* update bestcapacity */
10672  bestcapacity = MAX(bestcapacity, newcapacity);
10673  SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10674  }
10675 
10676  /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10677  if( freecapacity > 0 && freecapacity != consdata->capacity )
10678  {
10679  bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10680  SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10681  }
10682 
10683  /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10684  if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10685  {
10686  /* if demands[startindices[j]] == cap then exactly that job is running */
10687  SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10688  bestcapacity = consdata->capacity;
10689  break;
10690  }
10691  } /*lint --e{850}*/
10692 
10693  /* free all buffer arrays */
10694  SCIPfreeBufferArray(scip, &endindices);
10695  SCIPfreeBufferArray(scip, &startindices);
10696  SCIPfreeBufferArray(scip, &endtimes);
10697  SCIPfreeBufferArray(scip, &starttimes);
10698 
10699  /* check whether capacity can be tightened and whether demands need to be adjusted */
10700  if( bestcapacity < consdata->capacity )
10701  {
10702  SCIPdebug( int oldnchgcoefs = *nchgcoefs; )
10703 
10704  SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10705  SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10706 
10707  for( j = 0; j < nvars; ++j )
10708  {
10709  if( consdata->demands[j] == consdata->capacity )
10710  {
10711  consdata->demands[j] = bestcapacity;
10712  (*nchgcoefs)++;
10713  }
10714  }
10715 
10716  consdata->capacity = bestcapacity;
10717  (*nchgsides)++;
10718 
10719  SCIPdebug( SCIPdebugMsg(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs); )
10720 
10721  consdata->varbounds = FALSE;
10722  }
10723 
10724  return SCIP_OKAY;
10725 }
10726 
10727 /** tries to change coefficients:
10728  * demand_j < cap && all other parallel jobs in conflict
10729  * ==> set demand_j := cap
10730  */
10731 static
10733  SCIP* scip, /**< SCIP data structure */
10734  SCIP_CONS* cons, /**< cumulative constraint */
10735  int* nchgcoefs /**< pointer to count total number of changed coefficients */
10736  )
10737 {
10738  SCIP_CONSDATA* consdata;
10739  int nvars;
10740  int j;
10741  int oldnchgcoefs;
10742  int mindemand;
10743 
10744  assert(scip != NULL);
10745  assert(cons != NULL);
10746  assert(nchgcoefs != NULL);
10747 
10748  /* get constraint data for some parameter testings only! */
10749  consdata = SCIPconsGetData(cons);
10750  assert(consdata != NULL);
10751 
10752  nvars = consdata->nvars;
10753  oldnchgcoefs = *nchgcoefs;
10754 
10755  if( nvars <= 0 )
10756  return SCIP_OKAY;
10757 
10758  /* PRE1:
10759  * check all jobs j whether: r_j + r_min > capacity holds
10760  * if so: adjust r_j to capacity
10761  */
10762  mindemand = consdata->demands[0];
10763  for( j = 0; j < nvars; ++j )
10764  {
10765  mindemand = MIN(mindemand, consdata->demands[j]);
10766  }
10767 
10768  /*check each job */
10769  for( j = 0; j < nvars; ++j )
10770  {
10771  if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10772  {
10773  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10774  consdata->demands[j], consdata->capacity);
10775  consdata->demands[j] = consdata->capacity;
10776  (*nchgcoefs)++;
10777  }
10778  }
10779 
10780  /* PRE2:
10781  * check for each job (with d_j < cap)
10782  * whether it is disjunctive to all others over the time horizon
10783  */
10784  for( j = 0; j < nvars; ++j )
10785  {
10786  SCIP_Bool chgcoef;
10787  int est_j;
10788  int lct_j;
10789  int i;
10790 
10791  assert(consdata->demands[j] <= consdata->capacity);
10792 
10793  if( consdata->demands[j] == consdata->capacity )
10794  continue;
10795 
10796  chgcoef = TRUE;
10797 
10798  est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10799  lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10800 
10801  for( i = 0; i < nvars; ++i )
10802  {
10803  int est_i;
10804  int lct_i;
10805 
10806  if( i == j )
10807  continue;
10808 
10809  est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10810  lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10811 
10812  if( est_i >= lct_j || est_j >= lct_i )
10813  continue;
10814 
10815  if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10816  {
10817  chgcoef = FALSE;
10818  break;
10819  }
10820  }
10821 
10822  if( chgcoef )
10823  {
10824  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10825  consdata->demands[j], consdata->capacity);
10826  consdata->demands[j] = consdata->capacity;
10827  (*nchgcoefs)++;
10828  }
10829  }
10830 
10831  if( (*nchgcoefs) > oldnchgcoefs )
10832  {
10833  SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10834  (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10835  }
10836 
10837  return SCIP_OKAY;
10838 }
10839 
10840 #if 0
10841 /** try to reformulate constraint by replacing certain jobs */
10842 static
10843 SCIP_RETCODE reformulateCons(
10844  SCIP* scip, /**< SCIP data structure */
10845  SCIP_CONS* cons, /**< cumulative constraint */
10846  int* naggrvars /**< pointer to store the number of aggregated variables */
10847  )
10848 {
10849  SCIP_CONSDATA* consdata;
10850  int hmin;
10851  int hmax;
10852  int nvars;
10853  int v;
10854 
10855  consdata = SCIPconsGetData(cons);
10856  assert(cons != NULL);
10857 
10858  nvars = consdata->nvars;
10859  assert(nvars > 1);
10860 
10861  hmin = consdata->hmin;
10862  hmax = consdata->hmax;
10863  assert(hmin < hmax);
10864 
10865  for( v = 0; v < nvars; ++v )
10866  {
10867  SCIP_VAR* var;
10868  int duration;
10869  int est;
10870  int ect;
10871  int lst;
10872  int lct;
10873 
10874  var = consdata->vars[v];
10875  assert(var != NULL);
10876 
10877  duration = consdata->durations[v];
10878 
10879  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10880  ect = est + duration;
10881  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10882  lct = lst + duration;
10883 
10884  /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10885  assert(lst > hmin || ect < hmax);
10886 
10887  if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10888  {
10889  SCIP_VAR* aggrvar;
10890  char name[SCIP_MAXSTRLEN];
10891  SCIP_Bool infeasible;
10892  SCIP_Bool redundant;
10893  SCIP_Bool aggregated;
10894  int shift;
10895 
10896  shift = est - (hmin - lct + MIN(hmin, ect));
10897  assert(shift > 0);
10898  lst = hmin;
10899  duration = hmin - lct;
10900 
10901  SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10902  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10903 
10904  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10905  SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10907  SCIP_CALL( SCIPaddVar(scip, var) );
10908  SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10909 
10910  assert(!infeasible);
10911  assert(!redundant);
10912  assert(aggregated);
10913 
10914  /* replace variable */
10915  consdata->durations[v] = duration;
10916  consdata->vars[v] = aggrvar;
10917 
10918  /* remove and add locks */
10919  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10920  SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10921 
10922  SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10923 
10924  (*naggrvars)++;
10925  }
10926  }
10927 
10928  return SCIP_OKAY;
10929 }
10930 #endif
10931 
10932 /** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10933 static
10935  SCIP* scip, /**< SCIP data structure */
10936  SCIP_CONS* cons, /**< cumulative constraint */
10937  int* naddconss /**< pointer to store the number of added constraints */
10938  )
10939 {
10940  SCIP_CONSDATA* consdata;
10941  SCIP_VAR** vars;
10942  int* durations;
10943  int* demands;
10944  int capacity;
10945  int halfcapacity;
10946  int mindemand;
10947  int nvars;
10948  int v;
10949 
10950  consdata = SCIPconsGetData(cons);
10951  assert(consdata != NULL);
10952 
10953  capacity = consdata->capacity;
10954 
10955  if( capacity == 1 )
10956  return SCIP_OKAY;
10957 
10958  SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
10959  SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
10960  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10961 
10962  halfcapacity = capacity / 2;
10963  mindemand = consdata->capacity;
10964  nvars = 0;
10965 
10966  /* collect all jobs with demand larger than half of the capacity */
10967  for( v = 0; v < consdata->nvars; ++v )
10968  {
10969  if( consdata->demands[v] > halfcapacity )
10970  {
10971  vars[nvars] = consdata->vars[v];
10972  demands[nvars] = 1;
10973  durations[nvars] = consdata->durations[v];
10974  nvars++;
10975 
10976  mindemand = MIN(mindemand, consdata->demands[v]);
10977  }
10978  }
10979 
10980  if( nvars > 0 )
10981  {
10982  /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
10983  * job is still to large to be scheduled in parallel
10984  */
10985  for( v = 0; v < consdata->nvars; ++v )
10986  {
10987  if( consdata->demands[v] > halfcapacity )
10988  continue;
10989 
10990  if( mindemand + consdata->demands[v] > capacity )
10991  {
10992  demands[nvars] = 1;
10993  durations[nvars] = consdata->durations[v];
10994  vars[nvars] = consdata->vars[v];
10995  nvars++;
10996 
10997  /* @todo create one cumulative constraint and look for another small demand */
10998  break;
10999  }
11000  }
11001 
11002  /* creates cumulative constraint and adds it to problem */
11003  SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
11005  (*naddconss)++;
11006  }
11007 
11008  SCIPfreeBufferArray(scip, &demands);
11009  SCIPfreeBufferArray(scip, &durations);
11010  SCIPfreeBufferArray(scip, &vars);
11011 
11012  return SCIP_OKAY;
11013 }
11014 
11015 /** presolve given constraint */
11016 static
11018  SCIP* scip, /**< SCIP data structure */
11019  SCIP_CONS* cons, /**< cumulative constraint */
11020  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
11021  SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
11022  int* nfixedvars, /**< pointer to store the number of fixed variables */
11023 #if 0
11024  int* naggrvars, /**< pointer to counter which is increased by the number of deduced variable aggregations */
11025 #endif
11026  int* nchgbds, /**< pointer to store the number of changed bounds */
11027  int* ndelconss, /**< pointer to store the number of deleted constraints */
11028  int* naddconss, /**< pointer to store the number of added constraints */
11029  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
11030  int* nchgsides, /**< pointer to store the number of changed sides */
11031  SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
11032  SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
11033  )
11034 {
11035  assert(!SCIPconsIsDeleted(cons));
11036 
11037  /* only perform dual reductions on model constraints */
11038  if( conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) )
11039  {
11040  /* computes the effective horizon and checks if the constraint can be decomposed */
11041  SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11042 
11043  if( SCIPconsIsDeleted(cons) )
11044  return SCIP_OKAY;
11045 
11046  /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11047  * fixings (dual reductions)
11048  */
11049  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11050  {
11051  SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11052 
11053  if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11054  return SCIP_OKAY;
11055  }
11056 
11057  SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11058 
11059  if( *cutoff || SCIPconsIsDeleted(cons) )
11060  return SCIP_OKAY;
11061  }
11062 
11063  /* remove jobs which have a demand larger than the capacity */
11064  SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11065  assert((*cutoff) || checkDemands(scip, cons));
11066 
11067  if( *cutoff )
11068  return SCIP_OKAY;
11069 
11070  if( conshdlrdata->normalize )
11071  {
11072  /* divide demands by their greatest common divisor */
11073  normalizeDemands(scip, cons, nchgcoefs, nchgsides);
11074  }
11075 
11076  /* delete constraint with one job */
11077  SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11078 
11079  if( *cutoff || SCIPconsIsDeleted(cons) )
11080  return SCIP_OKAY;
11081 
11082  if( conshdlrdata->coeftightening )
11083  {
11084  /* try to tighten the capacity */
11085  SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11086 
11087  /* try to tighten the coefficients */
11088  SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11089  }
11090 
11091  assert(checkDemands(scip, cons) || *cutoff);
11092 
11093 #if 0
11094  SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11095 #endif
11096 
11097  return SCIP_OKAY;
11098 }
11099 
11100 /**@name TClique Graph callbacks
11101  *
11102  * @{
11103  */
11104 
11105 /** tclique graph data */
11106 struct TCLIQUE_Graph
11107 {
11108  SCIP_VAR** vars; /**< start time variables each of them is a node */
11109  SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11110  SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11111  SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11112  TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11113  int* ninarcs; /**< number if in arcs for the precedence graph */
11114  int* noutarcs; /**< number if out arcs for the precedence graph */
11115  int* durations; /**< for each node the duration of the corresponding job */
11116  int nnodes; /**< number of nodes */
11117  int size; /**< size of the array */
11118 };
11119 
11120 /** gets number of nodes in the graph */
11121 static
11122 TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11124  assert(tcliquegraph != NULL);
11125 
11126  return tcliquegraph->nnodes;
11127 }
11128 
11129 /** gets weight of nodes in the graph */
11130 static
11131 TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11133  assert(tcliquegraph != NULL);
11134 
11135  return tcliquegraph->weights;
11136 }
11137 
11138 /** returns, whether the edge (node1, node2) is in the graph */
11139 static
11140 TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11142  assert(tcliquegraph != NULL);
11143  assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11144  assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11145 
11146  /* check if an arc exits in the precedence graph */
11147  if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11148  return TRUE;
11149 
11150  /* check if an edge exits in the non-overlapping graph */
11151  if( tcliquegraph->demandmatrix[node1][node2] )
11152  return TRUE;
11153 
11154  return FALSE;
11155 }
11156 
11157 /** selects all nodes from a given set of nodes which are adjacent to a given node
11158  * and returns the number of selected nodes
11159  */
11160 static
11161 TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11163  int nadjnodes;
11164  int i;
11165 
11166  assert(tcliquegraph != NULL);
11167  assert(0 <= node && node < tcliquegraph->nnodes);
11168  assert(nnodes == 0 || nodes != NULL);
11169  assert(adjnodes != NULL);
11170 
11171  nadjnodes = 0;
11172 
11173  for( i = 0; i < nnodes; i++ )
11174  {
11175  /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11176  assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11177  assert(i == 0 || nodes[i-1] < nodes[i]);
11178 
11179  /* check if an edge exists */
11180  if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11181  {
11182  /* current node is adjacent to given node */
11183  adjnodes[nadjnodes] = nodes[i];
11184  nadjnodes++;
11185  }
11186  }
11187 
11188  return nadjnodes;
11189 }
11190 
11191 /** generates cuts using a clique found by algorithm for maximum weight clique
11192  * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11193  */
11194 static
11195 TCLIQUE_NEWSOL(tcliqueNewsolClique)
11196 { /*lint --e{715}*/
11197  SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11198 }
11199 
11200 /** print the tclique graph */
11201 #if 0
11202 static
11203 void tcliquePrint(
11204  SCIP* scip, /**< SCIP data structure */
11205  TCLIQUE_GRAPH* tcliquegraph /**< tclique graph */
11206  )
11207 {
11208  int nnodes;
11209  int i;
11210  int j;
11211 
11212  nnodes = tcliquegraph->nnodes;
11213 
11214  for( i = 0; i < nnodes; ++i )
11215  {
11216  for( j = 0; j < nnodes; ++j )
11217  {
11218  SCIPinfoMessage(scip, NULL, "(%d/%d) ", tcliquegraph->precedencematrix[i][j], tcliquegraph->demandmatrix[i][j]);
11219  }
11220  SCIPinfoMessage(scip, NULL, "\n");
11221  }
11222 }
11223 #endif
11224 
11225 /** @} */
11226 
11227 /** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11228  * job corresponding to variable bound variable (vlbvar)
11229  *
11230  * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11231  */
11232 static
11234  SCIP* scip, /**< SCIP data structure */
11235  SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11236  SCIP_Real vlbcoef, /**< variable bound coefficient */
11237  SCIP_Real vlbconst, /**< variable bound constant */
11238  int duration /**< duration of the variable bound variable */
11239  )
11240 {
11241  if( SCIPisEQ(scip, vlbcoef, 1.0) )
11242  {
11243  if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11244  {
11245  /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11246  return TRUE;
11247  }
11248  }
11249  else
11250  {
11251  SCIP_Real bound;
11252 
11253  bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11254 
11255  if( SCIPisLT(scip, vlbcoef, 1.0) )
11256  {
11257  SCIP_Real ub;
11258 
11259  ub = SCIPvarGetUbLocal(vlbvar);
11260 
11261  /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11262  if( SCIPisLE(scip, ub, bound) )
11263  return TRUE;
11264  }
11265  else
11266  {
11267  SCIP_Real lb;
11268 
11269  assert(SCIPisGT(scip, vlbcoef, 1.0));
11270 
11271  lb = SCIPvarGetLbLocal(vlbvar);
11272 
11273  /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11274  if( SCIPisGE(scip, lb, bound) )
11275  return TRUE;
11276  }
11277  }
11278 
11279  return FALSE;
11280 }
11281 
11282 /** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11283  * job corresponding to variable which is bounded (var)
11284  *
11285  * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11286  */
11287 static
11289  SCIP* scip, /**< SCIP data structure */
11290  SCIP_VAR* var, /**< variable which is bound from above */
11291  SCIP_Real vubcoef, /**< variable bound coefficient */
11292  SCIP_Real vubconst, /**< variable bound constant */
11293  int duration /**< duration of the variable which is bounded from above */
11294  )
11295 {
11296  SCIP_Real vlbcoef;
11297  SCIP_Real vlbconst;
11298 
11299  /* convert the variable upper bound into an variable lower bound */
11300  vlbcoef = 1.0 / vubcoef;
11301  vlbconst = -vubconst / vubcoef;
11302 
11303  return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11304 }
11305 
11306 /** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11307  * others an index larger than the number if active variables
11308  */
11309 static
11311  SCIP* scip, /**< SCIP data structure */
11312  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11313  SCIP_VAR* var, /**< variable for which we want the index */
11314  int* idx /**< pointer to store the index */
11315  )
11316 {
11317  (*idx) = SCIPvarGetProbindex(var);
11318 
11319  if( (*idx) == -1 )
11320  {
11321  if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11322  {
11323  (*idx) = SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var);
11324  }
11325  else
11326  {
11327  int pos;
11328  int v;
11329 
11330  /**@todo we might want to add the aggregation path to graph */
11331 
11332  /* check if we have to realloc memory */
11333  if( tcliquegraph->size == tcliquegraph->nnodes )
11334  {
11335  int size;
11336 
11337  size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11338  tcliquegraph->size = size;
11339 
11340  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11341  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11342  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11343  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11344  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11345 
11346  for( v = 0; v < tcliquegraph->nnodes; ++v )
11347  {
11348  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11349  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11350  }
11351  }
11352  assert(tcliquegraph->nnodes < tcliquegraph->size);
11353 
11354  pos = tcliquegraph->nnodes;
11355  assert(pos >= 0);
11356 
11357  tcliquegraph->durations[pos] = 0;
11358  tcliquegraph->weights[pos] = 0;
11359  tcliquegraph->vars[pos] = var;
11360 
11361  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11362  BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11363 
11364  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11365  BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11366 
11367  SCIP_CALL( SCIPhashmapInsertInt(tcliquegraph->varmap, (void*)var, pos) );
11368 
11369  tcliquegraph->nnodes++;
11370 
11371  for( v = 0; v < tcliquegraph->nnodes; ++v )
11372  {
11373  tcliquegraph->precedencematrix[v][pos] = 0;
11374  tcliquegraph->demandmatrix[v][pos] = 0;
11375  }
11376 
11377  (*idx) = tcliquegraph->nnodes;
11378  }
11379  }
11380  else
11381  {
11382  assert(*idx == SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var));
11383  }
11384 
11385  assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11386 
11387  return SCIP_OKAY;
11388 }
11389 
11390 /** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11391  *
11392  * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11393  * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11394  *
11395  * (i) b = 1 and c >= d
11396  * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11397  * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11398  *
11399  */
11400 static
11402  SCIP* scip, /**< SCIP data structure */
11403  TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11404  )
11405 {
11406  SCIP_VAR** vars;
11407  int nvars;
11408  int v;
11409 
11410  vars = SCIPgetVars(scip);
11411  nvars = SCIPgetNVars(scip);
11412 
11413  /* try to project each arc of the variable bound graph to precedence condition */
11414  for( v = 0; v < nvars; ++v )
11415  {
11416  SCIP_VAR** vbdvars;
11417  SCIP_VAR* var;
11418  SCIP_Real* vbdcoefs;
11419  SCIP_Real* vbdconsts;
11420  int nvbdvars;
11421  int idx1;
11422  int b;
11423 
11424  var = vars[v];
11425  assert(var != NULL);
11426 
11427  SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11428  assert(idx1 >= 0);
11429 
11430  if( tcliquegraph->durations[idx1] == 0 )
11431  continue;
11432 
11433  vbdvars = SCIPvarGetVlbVars(var);
11434  vbdcoefs = SCIPvarGetVlbCoefs(var);
11435  vbdconsts = SCIPvarGetVlbConstants(var);
11436  nvbdvars = SCIPvarGetNVlbs(var);
11437 
11438  for( b = 0; b < nvbdvars; ++b )
11439  {
11440  int idx2;
11441 
11442  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11443  assert(idx2 >= 0);
11444 
11445  if( tcliquegraph->durations[idx2] == 0 )
11446  continue;
11447 
11448  if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11449  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11450  }
11451 
11452  vbdvars = SCIPvarGetVubVars(var);
11453  vbdcoefs = SCIPvarGetVubCoefs(var);
11454  vbdconsts = SCIPvarGetVubConstants(var);
11455  nvbdvars = SCIPvarGetNVubs(var);
11456 
11457  for( b = 0; b < nvbdvars; ++b )
11458  {
11459  int idx2;
11460 
11461  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11462  assert(idx2 >= 0);
11463 
11464  if( tcliquegraph->durations[idx2] == 0 )
11465  continue;
11466 
11467  if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11468  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11469  }
11470 
11471  for( b = v+1; b < nvars; ++b )
11472  {
11473  int idx2;
11474 
11475  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11476  assert(idx2 >= 0);
11477 
11478  if( tcliquegraph->durations[idx2] == 0 )
11479  continue;
11480 
11481  /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11482  if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11483  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11484 
11485  /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11486  if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11487  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11488  }
11489  }
11490 
11491  return SCIP_OKAY;
11492 }
11493 
11494 /** compute the transitive closer of the given graph and the number of in and out arcs */
11495 static
11496 void transitiveClosure(
11497  SCIP_Bool** adjmatrix, /**< adjacent matrix */
11498  int* ninarcs, /**< array to store the number of in arcs */
11499  int* noutarcs, /**< array to store the number of out arcs */
11500  int nnodes /**< number if nodes */
11501  )
11502 {
11503  int i;
11504  int j;
11505  int k;
11506 
11507  for( i = 0; i < nnodes; ++i )
11508  {
11509  for( j = 0; j < nnodes; ++j )
11510  {
11511  if( adjmatrix[i][j] )
11512  {
11513  ninarcs[j]++;
11514  noutarcs[i]++;
11515 
11516  for( k = 0; k < nnodes; ++k )
11517  {
11518  if( adjmatrix[j][k] )
11519  adjmatrix[i][k] = TRUE;
11520  }
11521  }
11522  }
11523  }
11524 }
11525 
11526 /** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11527 static
11529  SCIP* scip, /**< SCIP data structure */
11530  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11531  SCIP_CONS** conss, /**< array of cumulative constraints */
11532  int nconss /**< number of cumulative constraints */
11533  )
11534 {
11535  int c;
11536 
11537  /* use the cumulative constraints to initialize the none overlapping graph */
11538  for( c = 0; c < nconss; ++c )
11539  {
11540  SCIP_CONSDATA* consdata;
11541  SCIP_VAR** vars;
11542  int* demands;
11543  int capacity;
11544  int nvars;
11545  int i;
11546 
11547  consdata = SCIPconsGetData(conss[c]);
11548  assert(consdata != NULL);
11549 
11550  vars = consdata->vars;
11551  demands = consdata->demands;
11552 
11553  nvars = consdata->nvars;
11554  capacity = consdata->capacity;
11555 
11556  SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11557 
11558  /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11559  for( i = 0; i < nvars; ++i )
11560  {
11561  int idx1;
11562  int j;
11563 
11564  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11565  assert(idx1 >= 0);
11566 
11567  if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11568  continue;
11569 
11570  for( j = i+1; j < nvars; ++j )
11571  {
11572  assert(consdata->durations[j] > 0);
11573 
11574  if( demands[i] + demands[j] > capacity )
11575  {
11576  int idx2;
11577  int est1;
11578  int est2;
11579  int lct1;
11580  int lct2;
11581 
11582  /* check if the effective horizon is large enough */
11583  est1 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[i]));
11584  est2 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[j]));
11585 
11586  /* at least one of the jobs needs to start at hmin or later */
11587  if( est1 < consdata->hmin && est2 < consdata->hmin )
11588  continue;
11589 
11590  lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11591  lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11592 
11593  /* at least one of the jobs needs to finish not later then hmin */
11594  if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11595  continue;
11596 
11597  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11598  assert(idx2 >= 0);
11599  assert(idx1 != idx2);
11600 
11601  if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11602  continue;
11603 
11604  SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11605 
11606  assert(tcliquegraph->durations[idx1] > 0);
11607  assert(tcliquegraph->durations[idx2] > 0);
11608 
11609  tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11610  tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11611  }
11612  }
11613  }
11614  }
11615 
11616  return SCIP_OKAY;
11617 }
11618 
11619 /** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11620  * of jobs cannot run in parallel
11621  */
11622 static
11624  SCIP* scip, /**< SCIP data structure */
11625  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11626  SCIP_CONS** conss, /**< array of cumulative constraints */
11627  int nconss /**< number of cumulative constraints */
11628  )
11629 {
11630  assert(scip != NULL);
11631  assert(tcliquegraph != NULL);
11632 
11633  /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11634  SCIP_CALL( projectVbd(scip, tcliquegraph) );
11635 
11636  /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11637  transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11638 
11639  /* constraints non-overlapping graph */
11640  SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11641 
11642  return SCIP_OKAY;
11643 }
11644 
11645 /** create cumulative constraint from conflict set */
11646 static
11648  SCIP* scip, /**< SCIP data structure */
11649  const char* name, /**< constraint name */
11650  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11651  int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11652  int ncliquenodes /**< number of nodes in the clique */
11653  )
11654 {
11655  SCIP_CONS* cons;
11656  SCIP_VAR** vars;
11657  int* durations;
11658  int* demands;
11659  int v;
11660 
11661  SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11662  SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11663  SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11664 
11665  SCIPsortInt(cliquenodes, ncliquenodes);
11666 
11667  /* collect variables, durations, and demands */
11668  for( v = 0; v < ncliquenodes; ++v )
11669  {
11670  durations[v] = tcliquegraph->durations[cliquenodes[v]];
11671  assert(durations[v] > 0);
11672  demands[v] = 1;
11673  vars[v] = tcliquegraph->vars[cliquenodes[v]];
11674  }
11675 
11676  /* create (unary) cumulative constraint */
11677  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11679 
11680  SCIP_CALL( SCIPaddCons(scip, cons) );
11681  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11682 
11683  /* free buffers */
11684  SCIPfreeBufferArray(scip, &demands);
11685  SCIPfreeBufferArray(scip, &durations);
11686  SCIPfreeBufferArray(scip, &vars);
11687 
11688  return SCIP_OKAY;
11689 }
11690 
11691 /** search for cumulative constrainst */
11692 static
11694  SCIP* scip, /**< SCIP data structure */
11695  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11696  int* naddconss /**< pointer to store the number of added constraints */
11697  )
11698 {
11699  TCLIQUE_STATUS tcliquestatus;
11700  SCIP_Bool* precedencerow;
11701  SCIP_Bool* precedencecol;
11702  SCIP_Bool* demandrow;
11703  SCIP_Bool* demandcol;
11704  SCIP_HASHTABLE* covered;
11705  int* cliquenodes;
11706  int ncliquenodes;
11707  int cliqueweight;
11708  int ntreenodes;
11709  int nnodes;
11710  int nconss;
11711  int v;
11712 
11713  nnodes = tcliquegraph->nnodes;
11714  nconss = 0;
11715 
11716  /* initialize the weight of each job with its duration */
11717  for( v = 0; v < nnodes; ++v )
11718  {
11719  tcliquegraph->weights[v] = tcliquegraph->durations[v];
11720  }
11721 
11722  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11723  SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11724  SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11725  SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11726  SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11727 
11728  /* create a hash table to store all start time variables which are already covered by at least one clique */
11729  SCIP_CALL( SCIPhashtableCreate(&covered, SCIPblkmem(scip), nnodes,
11730  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11731 
11732  /* for each variables/job we are ... */
11733  for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11734  {
11735  char name[SCIP_MAXSTRLEN];
11736  int c;
11737 
11738  /* jobs with zero durations are skipped */
11739  if( tcliquegraph->durations[v] == 0 )
11740  continue;
11741 
11742  /* check if the start time variable is already covered by at least one clique */
11743  if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11744  continue;
11745 
11746  SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11747 
11748  /* temporarily remove the connection via the precedence graph */
11749  for( c = 0; c < nnodes; ++c )
11750  {
11751  precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11752  precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11753 
11754  demandrow[c] = tcliquegraph->demandmatrix[v][c];
11755  demandcol[c] = tcliquegraph->demandmatrix[c][v];
11756 
11757 #if 0
11758  if( precedencerow[c] || precedencecol[c] )
11759  {
11760  tcliquegraph->demandmatrix[v][c] = FALSE;
11761  tcliquegraph->demandmatrix[c][v] = FALSE;
11762  }
11763 #endif
11764 
11765  tcliquegraph->precedencematrix[c][v] = FALSE;
11766  tcliquegraph->precedencematrix[v][c] = FALSE;
11767  }
11768 
11769  /* find (heuristically) maximum cliques which includes node v */
11770  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11771  tcliquegraph, tcliqueNewsolClique, NULL,
11772  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11773  10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11774 
11775  SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11776 
11777  if( ncliquenodes == 1 )
11778  continue;
11779 
11780  /* construct constraint name */
11781  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11782 
11783  SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11784  nconss++;
11785 
11786  /* all start time variable to covered hash table */
11787  for( c = 0; c < ncliquenodes; ++c )
11788  {
11789  SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11790  }
11791 
11792  /* copy the precedence relations back */
11793  for( c = 0; c < nnodes; ++c )
11794  {
11795  tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11796  tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11797 
11798  tcliquegraph->demandmatrix[v][c] = demandrow[c];
11799  tcliquegraph->demandmatrix[c][v] = demandcol[c];
11800  }
11801  }
11802 
11803  SCIPhashtableFree(&covered);
11804 
11805  SCIPfreeBufferArray(scip, &demandcol);
11806  SCIPfreeBufferArray(scip, &demandrow);
11807  SCIPfreeBufferArray(scip, &precedencecol);
11808  SCIPfreeBufferArray(scip, &precedencerow);
11809  SCIPfreeBufferArray(scip, &cliquenodes);
11810 
11811  (*naddconss) += nconss;
11812 
11813  /* for the statistic we count the number added disjunctive constraints */
11814  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11815 
11816  return SCIP_OKAY;
11817 }
11818 
11819 /** create precedence constraint (as variable bound constraint */
11820 static
11822  SCIP* scip, /**< SCIP data structure */
11823  const char* name, /**< constraint name */
11824  SCIP_VAR* var, /**< variable x that has variable bound */
11825  SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11826  int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11827  )
11828 {
11829  SCIP_CONS* cons;
11830 
11831  /* create variable bound constraint */
11832  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11834 
11835  SCIPdebugPrintCons(scip, cons, NULL);
11836 
11837  /* add constraint to problem and release it */
11838  SCIP_CALL( SCIPaddCons(scip, cons) );
11839  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11840 
11841  return SCIP_OKAY;
11842 }
11843 
11844 /** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11845 static
11847  SCIP* scip, /**< SCIP data structure */
11848  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11849  int source, /**< index of the source node */
11850  int sink, /**< index of the sink node */
11851  int* naddconss /**< pointer to store the number of added constraints */
11852  )
11853 {
11854  TCLIQUE_WEIGHT cliqueweight;
11855  TCLIQUE_STATUS tcliquestatus;
11856  SCIP_VAR** vars;
11857  int* cliquenodes;
11858  int nnodes;
11859  int lct;
11860  int est;
11861  int i;
11862 
11863  int ntreenodes;
11864  int ncliquenodes;
11865 
11866  /* check if source and sink are connencted */
11867  if( !tcliquegraph->precedencematrix[source][sink] )
11868  return SCIP_OKAY;
11869 
11870  nnodes = tcliquegraph->nnodes;
11871  vars = tcliquegraph->vars;
11872 
11873  /* reset the weights to zero */
11874  BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11875 
11876  /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11877  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11878  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[sink]));
11879 
11880  /* weight all jobs which run for sure between source and sink with their duration */
11881  for( i = 0; i < nnodes; ++i )
11882  {
11883  SCIP_VAR* var;
11884  int duration;
11885 
11886  var = vars[i];
11887  assert(var != NULL);
11888 
11889  duration = tcliquegraph->durations[i];
11890 
11891  if( i == source || i == sink )
11892  {
11893  /* source and sink are not weighted */
11894  tcliquegraph->weights[i] = 0;
11895  }
11896  else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11897  {
11898  /* job i runs after source and before sink */
11899  tcliquegraph->weights[i] = duration;
11900  }
11901  else if( lct <= SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var))
11902  && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11903  {
11904  /* job i run in between due the bounds of the start time variables */
11905  tcliquegraph->weights[i] = duration;
11906  }
11907  else
11908  tcliquegraph->weights[i] = 0;
11909  }
11910 
11911  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11912 
11913  /* find (heuristically) maximum cliques */
11914  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11915  tcliquegraph, tcliqueNewsolClique, NULL,
11916  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11917  10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11918 
11919  if( ncliquenodes > 1 )
11920  {
11921  char name[SCIP_MAXSTRLEN];
11922  int distance;
11923 
11924  /* construct constraint name */
11925  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11926 
11927  /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11928  * duration of the source job
11929  */
11930  distance = cliqueweight + tcliquegraph->durations[source];
11931 
11932  SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11933  (*naddconss)++;
11934  }
11935 
11936  SCIPfreeBufferArray(scip, &cliquenodes);
11937 
11938  return SCIP_OKAY;
11939 }
11940 
11941 /** search for precedence constraints
11942  *
11943  * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
11944  * corresponding two jobs
11945  */
11946 static
11948  SCIP* scip, /**< SCIP data structure */
11949  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11950  int* naddconss /**< pointer to store the number of added constraints */
11951  )
11952 {
11953  int* sources;
11954  int* sinks;
11955  int nconss;
11956  int nnodes;
11957  int nsources;
11958  int nsinks;
11959  int i;
11960 
11961  nnodes = tcliquegraph->nnodes;
11962  nconss = 0;
11963 
11964  nsources = 0;
11965  nsinks = 0;
11966 
11967  SCIP_CALL( SCIPallocBufferArray(scip, &sources, nnodes) );
11968  SCIP_CALL( SCIPallocBufferArray(scip, &sinks, nnodes) );
11969 
11970  /* first collect all sources and sinks */
11971  for( i = 0; i < nnodes; ++i )
11972  {
11973  if( tcliquegraph->ninarcs[i] == 0 )
11974  {
11975  sources[nsources] = i;
11976  nsources++;
11977  }
11978 
11979  if( tcliquegraph->ninarcs[i] == 0 )
11980  {
11981  sinks[nsinks] = i;
11982  nsinks++;
11983  }
11984  }
11985 
11986  /* compute for each node a minimum distance to each sources and each sink */
11987  for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
11988  {
11989  int j;
11990 
11991  for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
11992  {
11993  SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
11994  }
11995 
11996  for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
11997  {
11998  SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
11999  }
12000  }
12001 
12002  (*naddconss) += nconss;
12003 
12004  /* for the statistic we count the number added variable constraints */
12005  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
12006 
12007  SCIPfreeBufferArray(scip, &sinks);
12008  SCIPfreeBufferArray(scip, &sources);
12009 
12010  return SCIP_OKAY;
12011 }
12012 
12013 /** initialize the assumed durations for each variable */
12014 static
12016  SCIP* scip, /**< SCIP data structure */
12017  TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
12018  SCIP_CONS** conss, /**< cumulative constraints */
12019  int nconss /**< number of cumulative constraints */
12020  )
12021 {
12022  int c;
12023 
12024  /* use the cumulative structure to define the duration we are using for each job */
12025  for( c = 0; c < nconss; ++c )
12026  {
12027  SCIP_CONSDATA* consdata;
12028  SCIP_VAR** vars;
12029  int nvars;
12030  int v;
12031 
12032  consdata = SCIPconsGetData(conss[c]);
12033  assert(consdata != NULL);
12034 
12035  vars = consdata->vars;
12036  nvars = consdata->nvars;
12037 
12038  for( v = 0; v < nvars; ++v )
12039  {
12040  int idx;
12041 
12042  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12043  assert(idx >= 0);
12044 
12045  /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12046  * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12047  * general this is not the case. Therefore, the question would be which duration should be used?
12048  */
12049  tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12050  assert(tcliquegraph->durations[idx] > 0);
12051  }
12052  }
12053 
12054  return SCIP_OKAY;
12055 }
12056 
12057 /** create tclique graph */
12058 static
12060  SCIP* scip, /**< SCIP data structure */
12061  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12062  )
12063 {
12064  SCIP_VAR** vars;
12065  SCIP_HASHMAP* varmap;
12066  SCIP_Bool** precedencematrix;
12067  SCIP_Bool** demandmatrix;
12068  int* ninarcs;
12069  int* noutarcs;
12070  int* durations;
12071  int* weights;
12072  int nvars;
12073  int v;
12074 
12075  vars = SCIPgetVars(scip);
12076  nvars = SCIPgetNVars(scip);
12077 
12078  /* allocate memory for the tclique graph data structure */
12079  SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12080 
12081  /* create the variable mapping hash map */
12082  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
12083 
12084  /* each active variables get a node in the graph */
12085  SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12086 
12087  /* allocate memory for the projected variables bound graph and the none overlapping graph */
12088  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12089  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12090 
12091  /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12092  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12093  BMSclearMemoryArray(weights, nvars);
12094 
12095  /* array to store the number of in arc of the precedence graph */
12096  SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12097  BMSclearMemoryArray(ninarcs, nvars);
12098 
12099  /* array to store the number of out arc of the precedence graph */
12100  SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12101  BMSclearMemoryArray(noutarcs, nvars);
12102 
12103  /* array to store the used duration for each node */
12104  SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12105  BMSclearMemoryArray(durations, nvars);
12106 
12107  for( v = 0; v < nvars; ++v )
12108  {
12109  SCIP_VAR* var;
12110 
12111  var = vars[v];
12112  assert(var != NULL);
12113 
12114  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12115  BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12116 
12117  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12118  BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12119 
12120  /* insert all active variables into the garph */
12121  assert(SCIPvarGetProbindex(var) == v);
12122  SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)var, v) );
12123  }
12124 
12125  (*tcliquegraph)->nnodes = nvars;
12126  (*tcliquegraph)->varmap = varmap;
12127  (*tcliquegraph)->precedencematrix = precedencematrix;
12128  (*tcliquegraph)->demandmatrix = demandmatrix;
12129  (*tcliquegraph)->weights = weights;
12130  (*tcliquegraph)->ninarcs = ninarcs;
12131  (*tcliquegraph)->noutarcs = noutarcs;
12132  (*tcliquegraph)->durations = durations;
12133  (*tcliquegraph)->size = nvars;
12134 
12135  return SCIP_OKAY;
12136 }
12137 
12138 /** frees the tclique graph */
12139 static
12140 void freeTcliqueGraph(
12141  SCIP* scip, /**< SCIP data structure */
12142  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12143  )
12144 {
12145  int v;
12146 
12147  for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12148  {
12149  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12150  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12151  }
12152 
12153  SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12154  SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12155  SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12156  SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12157  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12158  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12159  SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12160  SCIPhashmapFree(&(*tcliquegraph)->varmap);
12161 
12162  SCIPfreeBuffer(scip, tcliquegraph);
12163 }
12164 
12165 /** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12166  * constrains (disjunctive constraint)
12167  */
12168 static
12170  SCIP* scip, /**< SCIP data structure */
12171  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12172  SCIP_CONS** conss, /**< array of cumulative constraints */
12173  int nconss, /**< number of cumulative constraints */
12174  int* naddconss /**< pointer to store the number of added constraints */
12175  )
12176 {
12177  TCLIQUE_GRAPH* tcliquegraph;
12178 
12179  /* create tclique graph */
12180  SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12181 
12182  /* define for each job a duration */
12183  SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12184 
12185  /* constuct incompatibility graph */
12186  SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12187 
12188  /* search for new precedence constraints */
12189  if( conshdlrdata->detectvarbounds )
12190  {
12191  SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12192  }
12193 
12194  /* search for new cumulative constraints */
12195  if( conshdlrdata->detectdisjunctive )
12196  {
12197  SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12198  }
12199 
12200  /* free tclique graph data structure */
12201  freeTcliqueGraph(scip, &tcliquegraph);
12202 
12203  return SCIP_OKAY;
12204 }
12205 
12206 /** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12207 static
12209  SCIP_CONSDATA* consdata /**< cumulative constraint data */
12210  )
12211 {
12212  SCIP_VAR** vars;
12213  int nvars;
12214  int v;
12215 
12216  if( consdata->validsignature )
12217  return;
12218 
12219  vars = consdata->vars;
12220  nvars = consdata->nvars;
12221 
12222  for( v = 0; v < nvars; ++v )
12223  {
12224  consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12225  }
12226 
12227  consdata->validsignature = TRUE;
12228 }
12229 
12230 /** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12231 static
12232 SCIP_DECL_SORTINDCOMP(consdataCompVar)
12233 { /*lint --e{715}*/
12234  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12235 
12236  assert(consdata != NULL);
12237  assert(0 <= ind1 && ind1 < consdata->nvars);
12238  assert(0 <= ind2 && ind2 < consdata->nvars);
12239 
12240  return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12241 }
12242 
12243 /** run a pairwise comparison */
12244 static
12246  SCIP* scip, /**< SCIP data structure */
12247  SCIP_CONS** conss, /**< array of cumulative constraints */
12248  int nconss, /**< number of cumulative constraints */
12249  int* ndelconss /**< pointer to store the number of deletedconstraints */
12250  )
12251 {
12252  int i;
12253  int j;
12254 
12255  for( i = 0; i < nconss; ++i )
12256  {
12257  SCIP_CONSDATA* consdata0;
12258  SCIP_CONS* cons0;
12259 
12260  cons0 = conss[i];
12261  assert(cons0 != NULL);
12262 
12263  consdata0 = SCIPconsGetData(cons0);
12264  assert(consdata0 != NULL);
12265 
12266  consdataCalcSignature(consdata0);
12267  assert(consdata0->validsignature);
12268 
12269  for( j = i+1; j < nconss; ++j )
12270  {
12271  SCIP_CONSDATA* consdata1;
12272  SCIP_CONS* cons1;
12273 
12274  cons1 = conss[j];
12275  assert(cons1 != NULL);
12276 
12277  consdata1 = SCIPconsGetData(cons1);
12278  assert(consdata1 != NULL);
12279 
12280  if( consdata0->capacity != consdata1->capacity )
12281  continue;
12282 
12283  consdataCalcSignature(consdata1);
12284  assert(consdata1->validsignature);
12285 
12286  if( (consdata1->signature & (~consdata0->signature)) == 0 )
12287  {
12288  SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12289  SCIPswapPointers((void**)&cons0, (void**)&cons1);
12290  assert((consdata0->signature & (~consdata1->signature)) == 0);
12291  }
12292 
12293  if( (consdata0->signature & (~consdata1->signature)) == 0 )
12294  {
12295  int* perm0;
12296  int* perm1;
12297  int v0;
12298  int v1;
12299 
12300  if( consdata0->nvars > consdata1->nvars )
12301  continue;
12302 
12303  if( consdata0->hmin < consdata1->hmin )
12304  continue;
12305 
12306  if( consdata0->hmax > consdata1->hmax )
12307  continue;
12308 
12309  SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12310  SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12311 
12312  /* call sorting method */
12313  SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12314  SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12315 
12316  for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12317  {
12318  SCIP_VAR* var0;
12319  SCIP_VAR* var1;
12320  int idx0;
12321  int idx1;
12322  int comp;
12323 
12324  idx0 = perm0[v0];
12325  idx1 = perm1[v1];
12326 
12327  var0 = consdata0->vars[idx0];
12328 
12329  var1 = consdata1->vars[idx1];
12330 
12331  comp = SCIPvarCompare(var0, var1);
12332 
12333  if( comp == 0 )
12334  {
12335  int duration0;
12336  int duration1;
12337  int demand0;
12338  int demand1;
12339 
12340  demand0 = consdata0->demands[idx0];
12341  duration0 = consdata0->durations[idx0];
12342 
12343  demand1 = consdata1->demands[idx1];
12344  duration1 = consdata1->durations[idx1];
12345 
12346  if( demand0 != demand1 )
12347  break;
12348 
12349  if( duration0 != duration1 )
12350  break;
12351 
12352  v0++;
12353  v1++;
12354  }
12355  else if( comp > 0 )
12356  v1++;
12357  else
12358  break;
12359  }
12360 
12361  if( v0 == consdata0->nvars )
12362  {
12363  if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12364  {
12365  initializeLocks(consdata1, TRUE);
12366  }
12367 
12368  /* coverity[swapped_arguments] */
12369  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12370 
12371  SCIP_CALL( SCIPdelCons(scip, cons0) );
12372  (*ndelconss)++;
12373  }
12374 
12375  SCIPfreeBufferArray(scip, &perm1);
12376  SCIPfreeBufferArray(scip, &perm0);
12377  }
12378  }
12379  }
12380 
12381  return SCIP_OKAY;
12382 }
12383 
12384 /** strengthen the variable bounds using the cumulative condition */
12385 static
12387  SCIP* scip, /**< SCIP data structure */
12388  SCIP_CONS* cons, /**< constraint to propagate */
12389  int* nchgbds, /**< pointer to store the number of changed bounds */
12390  int* naddconss /**< pointer to store the number of added constraints */
12391  )
12392 {
12393  SCIP_CONSDATA* consdata;
12394  SCIP_VAR** vars;
12395  int* durations;
12396  int* demands;
12397  int capacity;
12398  int nvars;
12399  int nconss;
12400  int i;
12401 
12402  consdata = SCIPconsGetData(cons);
12403  assert(consdata != NULL);
12404 
12405  /* check if the variable bounds got already strengthen by the cumulative constraint */
12406  if( consdata->varbounds )
12407  return SCIP_OKAY;
12408 
12409  vars = consdata->vars;
12410  durations = consdata->durations;
12411  demands = consdata->demands;
12412  capacity = consdata->capacity;
12413  nvars = consdata->nvars;
12414 
12415  nconss = 0;
12416 
12417  for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12418  {
12419  SCIP_VAR** vbdvars;
12420  SCIP_VAR* var;
12421  SCIP_Real* vbdcoefs;
12422  SCIP_Real* vbdconsts;
12423  int nvbdvars;
12424  int b;
12425  int j;
12426 
12427  var = consdata->vars[i];
12428  assert(var != NULL);
12429 
12430  vbdvars = SCIPvarGetVlbVars(var);
12431  vbdcoefs = SCIPvarGetVlbCoefs(var);
12432  vbdconsts = SCIPvarGetVlbConstants(var);
12433  nvbdvars = SCIPvarGetNVlbs(var);
12434 
12435  for( b = 0; b < nvbdvars; ++b )
12436  {
12437  if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12438  {
12439  if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12440  {
12441  for( j = 0; j < nvars; ++j )
12442  {
12443  if( vars[j] == vbdvars[b] )
12444  break;
12445  }
12446  if( j == nvars )
12447  continue;
12448 
12449  if( demands[i] + demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12450  {
12451  SCIP_Bool infeasible;
12452  char name[SCIP_MAXSTRLEN];
12453  int nlocalbdchgs;
12454 
12455  SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12456 
12457  /* construct constraint name */
12458  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12459 
12460  SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12461  nconss++;
12462 
12463  SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12464  assert(!infeasible);
12465 
12466  (*nchgbds) += nlocalbdchgs;
12467  }
12468  }
12469  }
12470  }
12471  }
12472 
12473  (*naddconss) += nconss;
12474 
12475  consdata->varbounds = TRUE;
12476 
12477  return SCIP_OKAY;
12478 }
12479 
12480 /** helper function to enforce constraints */
12481 static
12483  SCIP* scip, /**< SCIP data structure */
12484  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
12485  SCIP_CONS** conss, /**< constraints to process */
12486  int nconss, /**< number of constraints */
12487  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
12488  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
12489  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
12490  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
12491  )
12492 {
12493  SCIP_CONSHDLRDATA* conshdlrdata;
12494 
12495  assert(conshdlr != NULL);
12496  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12497  assert(nconss == 0 || conss != NULL);
12498  assert(result != NULL);
12499 
12500  if( solinfeasible )
12501  {
12502  *result = SCIP_INFEASIBLE;
12503  return SCIP_OKAY;
12504  }
12505 
12506  SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12507  sol == NULL ? "LP" : "relaxation");
12508 
12509  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12510  assert(conshdlrdata != NULL);
12511 
12512  (*result) = SCIP_FEASIBLE;
12513 
12514  if( conshdlrdata->usebinvars )
12515  {
12516  SCIP_Bool separated;
12517  SCIP_Bool cutoff;
12518  int c;
12519 
12520  separated = FALSE;
12521 
12522  /* first check if a constraints is violated */
12523  for( c = 0; c < nusefulconss; ++c )
12524  {
12525  SCIP_CONS* cons;
12526  SCIP_Bool violated;
12527 
12528  cons = conss[c];
12529  assert(cons != NULL);
12530 
12531  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12532 
12533  if( !violated )
12534  continue;
12535 
12536  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12537  if ( cutoff )
12538  {
12539  *result = SCIP_CUTOFF;
12540  return SCIP_OKAY;
12541  }
12542  }
12543 
12544  for( ; c < nconss && !separated; ++c )
12545  {
12546  SCIP_CONS* cons;
12547  SCIP_Bool violated;
12548 
12549  cons = conss[c];
12550  assert(cons != NULL);
12551 
12552  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12553 
12554  if( !violated )
12555  continue;
12556 
12557  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12558  if ( cutoff )
12559  {
12560  *result = SCIP_CUTOFF;
12561  return SCIP_OKAY;
12562  }
12563  }
12564 
12565  if( separated )
12566  (*result) = SCIP_SEPARATED;
12567  }
12568  else
12569  {
12570  SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12571  }
12572 
12573  return SCIP_OKAY;
12574 }
12575 
12576 /**@} */
12577 
12578 
12579 /**@name Callback methods of constraint handler
12580  *
12581  * @{
12582  */
12583 
12584 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12585 static
12586 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12587 { /*lint --e{715}*/
12588  assert(scip != NULL);
12589  assert(conshdlr != NULL);
12590  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12591 
12592  /* call inclusion method of constraint handler */
12594 
12596 
12597  *valid = TRUE;
12598 
12599  return SCIP_OKAY;
12600 }
12601 
12602 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12603 static
12604 SCIP_DECL_CONSFREE(consFreeCumulative)
12605 { /*lint --e{715}*/
12606  SCIP_CONSHDLRDATA* conshdlrdata;
12607 
12608  assert(conshdlr != NULL);
12609  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12610 
12611  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12612  assert(conshdlrdata != NULL);
12613 
12614 #ifdef SCIP_STATISTIC
12615  if( !conshdlrdata->iscopy )
12616  {
12617  /* statisitc output if SCIP_STATISTIC is defined */
12618  SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12619  conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12620  SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12621  conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12622  SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12623  conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12624  }
12625 #endif
12626 
12627  conshdlrdataFree(scip, &conshdlrdata);
12628 
12629  SCIPconshdlrSetData(conshdlr, NULL);
12630 
12631  return SCIP_OKAY;
12632 }
12633 
12634 
12635 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12636 static
12637 SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12638 { /*lint --e{715}*/
12639  SCIP_CONSHDLRDATA* conshdlrdata;
12640  int c;
12641 
12642  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12643  assert(conshdlrdata != NULL);
12644 
12645  conshdlrdata->detectedredundant = FALSE;
12646 
12647  for( c = 0; c < nconss; ++c )
12648  {
12649  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12650  * hmax)
12651  */
12652  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12653  }
12654 
12655  return SCIP_OKAY;
12656 }
12657 
12658 
12659 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12660 #ifdef SCIP_STATISTIC
12661 static
12662 SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12663 { /*lint --e{715}*/
12664  SCIP_CONSHDLRDATA* conshdlrdata;
12665  int c;
12666 
12667  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12668  assert(conshdlrdata != NULL);
12669 
12670  for( c = 0; c < nconss; ++c )
12671  {
12672  SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12673 
12674 #if 0
12675  SCIP_CALL( SCIPvisualizeConsCumulative(scip, conss[c]) );
12676 #endif
12677  }
12678 
12679  if( !conshdlrdata->iscopy )
12680  {
12681  SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12682  SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12683  SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12684  SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12685  SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12686  SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12687  SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12688  SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12689  SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12690  }
12691 
12692  return SCIP_OKAY;
12693 }
12694 #endif
12695 
12696 
12697 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12698 static
12699 SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12700 { /*lint --e{715}*/
12701  SCIP_CONSDATA* consdata;
12702  int c;
12703 
12704  assert(conshdlr != NULL);
12705  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12706 
12707  /* release the rows of all constraints */
12708  for( c = 0; c < nconss; ++c )
12709  {
12710  consdata = SCIPconsGetData(conss[c]);
12711  assert(consdata != NULL);
12712 
12713  /* free rows */
12714  SCIP_CALL( consdataFreeRows(scip, &consdata) );
12715  }
12716 
12717  return SCIP_OKAY;
12718 }
12719 
12720 /** frees specific constraint data */
12721 static
12722 SCIP_DECL_CONSDELETE(consDeleteCumulative)
12723 { /*lint --e{715}*/
12724  assert(conshdlr != NULL);
12725  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12726  assert(consdata != NULL );
12727  assert(*consdata != NULL );
12728 
12729  /* if constraint belongs to transformed problem space, drop bound change events on variables */
12730  if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12731  {
12732  SCIP_CONSHDLRDATA* conshdlrdata;
12733 
12734  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12735  assert(conshdlrdata != NULL);
12736 
12737  SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12738  }
12739 
12740  /* free cumulative constraint data */
12741  SCIP_CALL( consdataFree(scip, consdata) );
12742 
12743  return SCIP_OKAY;
12744 }
12745 
12746 /** transforms constraint data into data belonging to the transformed problem */
12747 static
12748 SCIP_DECL_CONSTRANS(consTransCumulative)
12749 { /*lint --e{715}*/
12750  SCIP_CONSHDLRDATA* conshdlrdata;
12751  SCIP_CONSDATA* sourcedata;
12752  SCIP_CONSDATA* targetdata;
12753 
12754  assert(conshdlr != NULL);
12755  assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
12756  assert(sourcecons != NULL);
12757  assert(targetcons != NULL);
12758 
12759  sourcedata = SCIPconsGetData(sourcecons);
12760  assert(sourcedata != NULL);
12761  assert(sourcedata->demandrows == NULL);
12762 
12763  SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12764 
12765  /* get event handler */
12766  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12767  assert(conshdlrdata != NULL);
12768  assert(conshdlrdata->eventhdlr != NULL);
12769 
12770  /* create constraint data for target constraint */
12771  SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12772  sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12773  sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12774 
12775  /* create target constraint */
12776  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12777  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12778  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12779  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12780  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12781 
12782  /* catch bound change events of variables */
12783  SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12784 
12785  return SCIP_OKAY;
12786 }
12787 
12788 /** LP initialization method of constraint handler */
12789 static
12790 SCIP_DECL_CONSINITLP(consInitlpCumulative)
12792  SCIP_CONSHDLRDATA* conshdlrdata;
12793  int c;
12794 
12795  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12796  assert(conshdlr != NULL);
12797  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12798  assert(conshdlrdata != NULL);
12799 
12800  *infeasible = FALSE;
12801 
12802  SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12803 
12804  if( conshdlrdata->usebinvars )
12805  {
12806  /* add rows to LP */
12807  for( c = 0; c < nconss && !(*infeasible); ++c )
12808  {
12809  assert(SCIPconsIsInitial(conss[c]));
12810  SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12811 
12812  if( conshdlrdata->cutsasconss )
12813  {
12814  SCIP_CALL( SCIPrestartSolve(scip) );
12815  }
12816  }
12817  }
12818 
12819  /**@todo if we want to use only the integer variables; only these will be in cuts
12820  * create some initial cuts, currently these are only separated */
12821 
12822  return SCIP_OKAY;
12823 }
12824 
12825 /** separation method of constraint handler for LP solutions */
12826 static
12827 SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12829  SCIP_CONSHDLRDATA* conshdlrdata;
12830  SCIP_Bool cutoff;
12831  SCIP_Bool separated;
12832  int c;
12833 
12834  SCIPdebugMsg(scip, "consSepalpCumulative\n");
12835 
12836  assert(conshdlr != NULL);
12837  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12838  assert(nconss == 0 || conss != NULL);
12839  assert(result != NULL);
12840  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12841  assert(conshdlrdata != NULL);
12842 
12843  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12844 
12845  cutoff = FALSE;
12846  separated = FALSE;
12847  (*result) = SCIP_DIDNOTRUN;
12848 
12849  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12850  return SCIP_OKAY;
12851 
12852  (*result) = SCIP_DIDNOTFIND;
12853 
12854  if( conshdlrdata->usebinvars )
12855  {
12856  /* check all useful cumulative constraints for feasibility */
12857  for( c = 0; c < nusefulconss && !cutoff; ++c )
12858  {
12859  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12860  }
12861 
12862  if( !cutoff && conshdlrdata->usecovercuts )
12863  {
12864  for( c = 0; c < nusefulconss; ++c )
12865  {
12866  SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12867  }
12868  }
12869  }
12870 
12871  if( conshdlrdata->sepaold )
12872  {
12873  /* separate cuts containing only integer variables */
12874  for( c = 0; c < nusefulconss; ++c )
12875  {
12876  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12877  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12878  }
12879  }
12880 
12881  if( cutoff )
12882  *result = SCIP_CUTOFF;
12883  else if( separated )
12884  *result = SCIP_SEPARATED;
12885 
12886  return SCIP_OKAY;
12887 }
12888 
12889 /** separation method of constraint handler for arbitrary primal solutions */
12890 static
12891 SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12892 { /*lint --e{715}*/
12893  SCIP_CONSHDLRDATA* conshdlrdata;
12894  SCIP_Bool cutoff;
12895  SCIP_Bool separated;
12896  int c;
12897 
12898  assert(conshdlr != NULL);
12899  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12900  assert(nconss == 0 || conss != NULL);
12901  assert(result != NULL);
12902 
12903  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12904  assert(conshdlrdata != NULL);
12905 
12906  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12907  return SCIP_OKAY;
12908 
12909  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12910 
12911  cutoff = FALSE;
12912  separated = FALSE;
12913  (*result) = SCIP_DIDNOTFIND;
12914 
12915  if( conshdlrdata->usebinvars )
12916  {
12917  /* check all useful cumulative constraints for feasibility */
12918  for( c = 0; c < nusefulconss && !cutoff; ++c )
12919  {
12920  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12921  }
12922 
12923  if( !cutoff && conshdlrdata->usecovercuts )
12924  {
12925  for( c = 0; c < nusefulconss; ++c )
12926  {
12927  SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12928  }
12929  }
12930  }
12931  if( conshdlrdata->sepaold )
12932  {
12933  /* separate cuts containing only integer variables */
12934  for( c = 0; c < nusefulconss; ++c )
12935  {
12936  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12937  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12938  }
12939  }
12940 
12941  if( cutoff )
12942  *result = SCIP_CUTOFF;
12943  else if( separated )
12944  *result = SCIP_SEPARATED;
12945 
12946  return SCIP_OKAY;
12947 }
12948 
12949 /** constraint enforcing method of constraint handler for LP solutions */
12950 static
12951 SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
12952 { /*lint --e{715}*/
12953  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
12954 
12955  return SCIP_OKAY;
12956 }
12957 
12958 /** constraint enforcing method of constraint handler for relaxation solutions */
12959 static
12960 SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
12961 { /*lint --e{715}*/
12962  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
12963 
12964  return SCIP_OKAY;
12965 }
12966 
12967 /** constraint enforcing method of constraint handler for pseudo solutions */
12968 static
12969 SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
12970 { /*lint --e{715}*/
12971  SCIP_CONSHDLRDATA* conshdlrdata;
12972 
12973  SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
12974 
12975  assert(conshdlr != NULL);
12976  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12977  assert(nconss == 0 || conss != NULL);
12978  assert(result != NULL);
12979 
12980  if( objinfeasible )
12981  {
12982  *result = SCIP_DIDNOTRUN;
12983  return SCIP_OKAY;
12984  }
12985 
12986  (*result) = SCIP_FEASIBLE;
12987 
12988  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12989  assert(conshdlrdata != NULL);
12990 
12991  SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
12992 
12993  return SCIP_OKAY;
12994 }
12995 
12996 /** feasibility check method of constraint handler for integral solutions */
12997 static
12998 SCIP_DECL_CONSCHECK(consCheckCumulative)
12999 { /*lint --e{715}*/
13000  int c;
13001 
13002  assert(conshdlr != NULL);
13003  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13004  assert(nconss == 0 || conss != NULL);
13005  assert(result != NULL);
13006 
13007  *result = SCIP_FEASIBLE;
13008 
13009  SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
13010 
13011  for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
13012  {
13013  SCIP_Bool violated = FALSE;
13014 
13015  SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
13016 
13017  if( violated )
13018  *result = SCIP_INFEASIBLE;
13019  }
13020 
13021  return SCIP_OKAY;
13022 }
13023 
13024 /** domain propagation method of constraint handler */
13025 static
13026 SCIP_DECL_CONSPROP(consPropCumulative)
13027 { /*lint --e{715}*/
13028  SCIP_CONSHDLRDATA* conshdlrdata;
13029  SCIP_Bool cutoff;
13030  int nchgbds;
13031  int ndelconss;
13032  int c;
13033 #if 0
13034  int naggrvars = 0;
13035 #endif
13036 
13037  SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
13038 
13039  assert(conshdlr != NULL);
13040  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13041  assert(nconss == 0 || conss != NULL);
13042  assert(result != NULL);
13043 
13044  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13045  assert(conshdlrdata != NULL);
13046 
13047  nchgbds = 0;
13048  ndelconss = 0;
13049  cutoff = FALSE;
13050  (*result) = SCIP_DIDNOTRUN;
13051 
13052  /* propgate all useful constraints */
13053  for( c = 0; c < nusefulconss && !cutoff; ++c )
13054  {
13055  SCIP_CONS* cons;
13056 
13057  cons = conss[c];
13058  assert(cons != NULL);
13059 
13060  if( SCIPgetDepth(scip) == 0 )
13061  {
13062 #if 0
13063  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13064  &nchgbds, &naggrvars, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13065 #else
13066  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13067  &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13068 #endif
13069  if( cutoff )
13070  break;
13071 
13072  if( SCIPconsIsDeleted(cons) )
13073  continue;
13074  }
13075 
13076  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13077  }
13078 
13079  if( !cutoff && nchgbds == 0 )
13080  {
13081  /* propgate all other constraints */
13082  for( c = nusefulconss; c < nconss && !cutoff; ++c )
13083  {
13084  SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13085  }
13086  }
13087 
13088 #if 0
13089  if( !cutoff && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 )
13090  {
13091  SCIP_CALL( propagateAllConss(scip, conss, nconss, TRUE, &nchgbds, &cutoff, NULL) );
13092  }
13093 #endif
13094 
13095  if( cutoff )
13096  {
13097  SCIPdebugMsg(scip, "detected infeasible\n");
13098  *result = SCIP_CUTOFF;
13099  }
13100  else if( nchgbds > 0 )
13101  {
13102  SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13103  *result = SCIP_REDUCEDDOM;
13104  }
13105  else
13106  *result = SCIP_DIDNOTFIND;
13107 
13108  return SCIP_OKAY;
13109 }
13110 
13111 /** presolving method of constraint handler */
13112 static
13113 SCIP_DECL_CONSPRESOL(consPresolCumulative)
13114 { /*lint --e{715}*/
13115  SCIP_CONSHDLRDATA* conshdlrdata;
13116  SCIP_CONS* cons;
13117  SCIP_Bool cutoff;
13118  SCIP_Bool unbounded;
13119  int oldnfixedvars;
13120  int oldnchgbds;
13121  int oldndelconss;
13122  int oldnaddconss;
13123  int oldnupgdconss;
13124  int oldnchgsides;
13125  int oldnchgcoefs;
13126  int c;
13127 
13128  assert(conshdlr != NULL);
13129  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13130  assert(scip != NULL);
13131  assert(result != NULL);
13132 
13133  SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13134 
13135  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13136  assert(conshdlrdata != NULL);
13137 
13138  *result = SCIP_DIDNOTRUN;
13139 
13140  oldnfixedvars = *nfixedvars;
13141  oldnchgbds = *nchgbds;
13142  oldnchgsides = *nchgsides;
13143  oldnchgcoefs = *nchgcoefs;
13144  oldnupgdconss = *nupgdconss;
13145  oldndelconss = *ndelconss;
13146  oldnaddconss = *naddconss;
13147  cutoff = FALSE;
13148  unbounded = FALSE;
13149 
13150  /* process constraints */
13151  for( c = 0; c < nconss && !cutoff; ++c )
13152  {
13153  cons = conss[c];
13154 
13155  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13156  * hmax)
13157  */
13158  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13159 
13160  if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13161  {
13162 #if 0
13163  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13164  nfixedvars, naggrvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13165 #else
13166  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13167  nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13168 #endif
13169 
13170  if( cutoff || unbounded )
13171  break;
13172 
13173  if( SCIPconsIsDeleted(cons) )
13174  continue;
13175  }
13176 
13177  /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13178  if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13179  {
13180  SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13181  }
13182 
13183  /* strengthen existing variable bounds using the cumulative condition */
13184  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13185  {
13186  SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13187  }
13188 
13189  /* propagate cumulative constraint */
13190  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13191  assert(checkDemands(scip, cons) || cutoff);
13192  }
13193 
13194  if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13195  {
13196  SCIP_CALL( propagateAllConss(scip, conss, nconss, FALSE, nfixedvars, &cutoff, NULL) );
13197  }
13198 
13199  /* only perform the detection of variable bounds and disjunctive constraint once */
13200  if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13201  && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13202  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13203  {
13204  /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13205  * propagation
13206  */
13207  SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13208  conshdlrdata->detectedredundant = TRUE;
13209  }
13210 
13211  if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13212  {
13213  SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13214  }
13215 
13216  SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13217  *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13218 
13219  if( cutoff )
13220  *result = SCIP_CUTOFF;
13221  else if( unbounded )
13222  *result = SCIP_UNBOUNDED;
13223  else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13224  || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13225  *result = SCIP_SUCCESS;
13226  else
13227  *result = SCIP_DIDNOTFIND;
13228 
13229  return SCIP_OKAY;
13230 }
13231 
13232 /** propagation conflict resolving method of constraint handler */
13233 static
13234 SCIP_DECL_CONSRESPROP(consRespropCumulative)
13235 { /*lint --e{715}*/
13236  SCIP_CONSHDLRDATA* conshdlrdata;
13237  SCIP_CONSDATA* consdata;
13238 
13239  assert(conshdlr != NULL);
13240  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13241  assert(scip != NULL);
13242  assert(result != NULL);
13243  assert(infervar != NULL);
13244  assert(bdchgidx != NULL);
13245 
13246  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13247  assert(conshdlrdata != NULL);
13248 
13249  /* process constraint */
13250  assert(cons != NULL);
13251 
13252  consdata = SCIPconsGetData(cons);
13253  assert(consdata != NULL);
13254 
13255  SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13256  SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13257  SCIPgetHminCumulative(scip, cons), SCIPgetHmaxCumulative(scip, cons));
13258 
13259  SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13260  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13261  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13262 
13263  return SCIP_OKAY;
13264 }
13265 
13266 /** variable rounding lock method of constraint handler */
13267 static
13268 SCIP_DECL_CONSLOCK(consLockCumulative)
13269 { /*lint --e{715}*/
13270  SCIP_CONSDATA* consdata;
13271  SCIP_VAR** vars;
13272  int v;
13273 
13274  SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13275 
13276  assert(scip != NULL);
13277  assert(cons != NULL);
13278  assert(locktype == SCIP_LOCKTYPE_MODEL);
13279 
13280  consdata = SCIPconsGetData(cons);
13281  assert(consdata != NULL);
13282 
13283  vars = consdata->vars;
13284  assert(vars != NULL);
13285 
13286  for( v = 0; v < consdata->nvars; ++v )
13287  {
13288  if( consdata->downlocks[v] && consdata->uplocks[v] )
13289  {
13290  /* the integer start variable should not get rounded in both direction */
13291  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
13292  }
13293  else if( consdata->downlocks[v] )
13294  {
13295  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
13296  }
13297  else if( consdata->uplocks[v] )
13298  {
13299  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
13300  }
13301  }
13302 
13303  return SCIP_OKAY;
13304 }
13305 
13306 
13307 /** constraint display method of constraint handler */
13308 static
13309 SCIP_DECL_CONSPRINT(consPrintCumulative)
13310 { /*lint --e{715}*/
13311  assert(scip != NULL);
13312  assert(conshdlr != NULL);
13313  assert(cons != NULL);
13314 
13315  consdataPrint(scip, SCIPconsGetData(cons), file);
13316 
13317  return SCIP_OKAY;
13318 }
13319 
13320 /** constraint copying method of constraint handler */
13321 static
13322 SCIP_DECL_CONSCOPY(consCopyCumulative)
13323 { /*lint --e{715}*/
13324  SCIP_CONSDATA* sourceconsdata;
13325  SCIP_VAR** sourcevars;
13326  SCIP_VAR** vars;
13327  const char* consname;
13328 
13329  int nvars;
13330  int v;
13331 
13332  sourceconsdata = SCIPconsGetData(sourcecons);
13333  assert(sourceconsdata != NULL);
13334 
13335  /* get variables of the source constraint */
13336  nvars = sourceconsdata->nvars;
13337  sourcevars = sourceconsdata->vars;
13338 
13339  (*valid) = TRUE;
13340 
13341  if( nvars == 0 )
13342  return SCIP_OKAY;
13343 
13344  /* allocate buffer array */
13345  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13346 
13347  for( v = 0; v < nvars && *valid; ++v )
13348  {
13349  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13350  assert(!(*valid) || vars[v] != NULL);
13351  }
13352 
13353  /* only create the target constraint, if all variables could be copied */
13354  if( *valid )
13355  {
13356  if( name != NULL )
13357  consname = name;
13358  else
13359  consname = SCIPconsGetName(sourcecons);
13360 
13361  /* create a copy of the cumulative constraint */
13362  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13363  sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13364  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13365 
13366  /* adjust left side if the time axis if needed */
13367  if( sourceconsdata->hmin > 0 )
13368  {
13369  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13370  }
13371 
13372  /* adjust right side if the time axis if needed */
13373  if( sourceconsdata->hmax < INT_MAX )
13374  {
13375  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13376  }
13377  }
13378 
13379  /* free buffer array */
13380  SCIPfreeBufferArray(scip, &vars);
13381 
13382  return SCIP_OKAY;
13383 }
13384 
13385 
13386 /** constraint parsing method of constraint handler */
13387 static
13388 SCIP_DECL_CONSPARSE(consParseCumulative)
13389 { /*lint --e{715}*/
13390  SCIP_VAR** vars;
13391  SCIP_VAR* var;
13392  SCIP_Real value;
13393  char strvalue[SCIP_MAXSTRLEN];
13394  char* endptr;
13395  int* demands;
13396  int* durations;
13397  int capacity;
13398  int duration;
13399  int demand;
13400  int hmin;
13401  int hmax;
13402  int varssize;
13403  int nvars;
13404 
13405  SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13406 
13407  /* cutoff "cumulative" form the constraint string */
13408  SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13409  str = endptr;
13410 
13411  varssize = 100;
13412  nvars = 0;
13413 
13414  /* allocate buffer array for variables */
13415  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13416  SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13417  SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13418 
13419  do
13420  {
13421  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13422 
13423  if( var != NULL )
13424  {
13425  str = endptr;
13426 
13427  SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13428  duration = atoi(strvalue);
13429  str = endptr;
13430 
13431  SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13432  demand = atoi(strvalue);
13433  str = endptr;
13434 
13435  SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13436 
13437  vars[nvars] = var;
13438  demands[nvars] = demand;
13439  durations[nvars] = duration;
13440  nvars++;
13441  }
13442  }
13443  while( var != NULL );
13444 
13445  /* parse effective time window */
13446  SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13447  hmin = atoi(strvalue);
13448  str = endptr;
13449 
13450  if( SCIPstrToRealValue(str, &value, &endptr) )
13451  {
13452  hmax = (int)(value);
13453  str = endptr;
13454 
13455  /* parse capacity */
13456  SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13457  str = endptr;
13458  if( SCIPstrToRealValue(str, &value, &endptr) )
13459  {
13460  capacity = (int)value;
13461 
13462  /* create cumulative constraint */
13463  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13464  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13465 
13466  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13467  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13468 
13469  (*success) = TRUE;
13470  }
13471  }
13472 
13473  /* free buffer arrays */
13474  SCIPfreeBufferArray(scip, &durations);
13475  SCIPfreeBufferArray(scip, &demands);
13476  SCIPfreeBufferArray(scip, &vars);
13477 
13478  return SCIP_OKAY;
13479 }
13480 
13481 /** constraint method of constraint handler which returns the variables (if possible) */
13482 static
13483 SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13484 { /*lint --e{715}*/
13485  SCIP_CONSDATA* consdata;
13486 
13487  consdata = SCIPconsGetData(cons);
13488  assert(consdata != NULL);
13489 
13490  if( varssize < consdata->nvars )
13491  (*success) = FALSE;
13492  else
13493  {
13494  assert(vars != NULL);
13495 
13496  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13497  (*success) = TRUE;
13498  }
13499 
13500  return SCIP_OKAY;
13501 }
13502 
13503 /** constraint method of constraint handler which returns the number of variables (if possible) */
13504 static
13505 SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13506 { /*lint --e{715}*/
13507  SCIP_CONSDATA* consdata;
13508 
13509  consdata = SCIPconsGetData(cons);
13510  assert(consdata != NULL);
13511 
13512  (*nvars) = consdata->nvars;
13513  (*success) = TRUE;
13514 
13515  return SCIP_OKAY;
13516 }
13517 
13518 /**@} */
13519 
13520 /**@name Callback methods of event handler
13521  *
13522  * @{
13523  */
13524 
13525 
13526 /** execution method of event handler */
13527 static
13528 SCIP_DECL_EVENTEXEC(eventExecCumulative)
13529 { /*lint --e{715}*/
13530  SCIP_CONSDATA* consdata;
13531 
13532  assert(scip != NULL);
13533  assert(eventhdlr != NULL);
13534  assert(eventdata != NULL);
13535  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13536  assert(event != NULL);
13537 
13538  consdata = (SCIP_CONSDATA*)eventdata;
13539  assert(consdata != NULL);
13540 
13541  /* mark the constraint to be not propagated */
13542  consdata->propagated = FALSE;
13543 
13544  return SCIP_OKAY;
13545 }
13546 
13547 /**@} */
13548 
13549 /**@name Interface methods
13550  *
13551  * @{
13552  */
13553 
13554 /*
13555  * constraint specific interface methods
13556  */
13557 
13558 /** creates the handler for cumulative constraints and includes it in SCIP */
13560  SCIP* scip /**< SCIP data structure */
13561  )
13562 {
13563  SCIP_CONSHDLRDATA* conshdlrdata;
13564  SCIP_CONSHDLR* conshdlr;
13565  SCIP_EVENTHDLR* eventhdlr;
13566 
13567  /* create event handler for bound change events */
13568  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13569 
13570  /* create cumulative constraint handler data */
13571  SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13572 
13573  /* include constraint handler */
13576  consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13577  conshdlrdata) );
13578 
13579  assert(conshdlr != NULL);
13580 
13581  /* set non-fundamental callbacks via specific setter functions */
13582  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13583  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13584 #ifdef SCIP_STATISTIC
13585  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13586 #endif
13587  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13588  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13589  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13590  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13591  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13592  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13593  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13594  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13596  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13597  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropCumulative, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13599  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13600  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13602  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13603  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
13604 
13605  /* add cumulative constraint handler parameters */
13607  "constraints/" CONSHDLR_NAME "/ttinfer",
13608  "should time-table (core-times) propagator be used to infer bounds?",
13609  &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13611  "constraints/" CONSHDLR_NAME "/efcheck",
13612  "should edge-finding be used to detect an overload?",
13613  &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13615  "constraints/" CONSHDLR_NAME "/efinfer",
13616  "should edge-finding be used to infer bounds?",
13617  &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13619  "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13620  &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13622  "constraints/" CONSHDLR_NAME "/ttefcheck",
13623  "should time-table edge-finding be used to detect an overload?",
13624  &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13626  "constraints/" CONSHDLR_NAME "/ttefinfer",
13627  "should time-table edge-finding be used to infer bounds?",
13628  &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13629 
13631  "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13632  &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13634  "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13635  &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13637  "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13638  &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13640  "constraints/" CONSHDLR_NAME "/cutsasconss",
13641  "should the cumulative constraint create cuts as knapsack constraints?",
13642  &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13644  "constraints/" CONSHDLR_NAME "/sepaold",
13645  "shall old sepa algo be applied?",
13646  &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13647 
13649  "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13650  &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13651 
13652  /* presolving parameters */
13654  "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13655  &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13657  "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13658  &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13660  "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13661  &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13663  "constraints/" CONSHDLR_NAME "/presolpairwise",
13664  "should pairwise constraint comparison be performed in presolving?",
13665  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13667  "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13668  &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13669 
13671  "constraints/" CONSHDLR_NAME "/maxnodes",
13672  "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13673  &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13675  "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13676  &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13678  "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13679  &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13680 
13681  /* conflict analysis parameters */
13683  "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13684  &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13685 
13686  return SCIP_OKAY;
13687 }
13688 
13689 /** creates and captures a cumulative constraint */
13691  SCIP* scip, /**< SCIP data structure */
13692  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13693  const char* name, /**< name of constraint */
13694  int nvars, /**< number of variables (jobs) */
13695  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13696  int* durations, /**< array containing corresponding durations */
13697  int* demands, /**< array containing corresponding demands */
13698  int capacity, /**< available cumulative capacity */
13699  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13700  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13701  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13702  * Usually set to TRUE. */
13703  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13704  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13705  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13706  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13707  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13708  * Usually set to TRUE. */
13709  SCIP_Bool local, /**< is constraint only valid locally?
13710  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13711  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13712  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13713  * adds coefficients to this constraint. */
13714  SCIP_Bool dynamic, /**< is constraint subject to aging?
13715  * Usually set to FALSE. Set to TRUE for own cuts which
13716  * are seperated as constraints. */
13717  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13718  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13719  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13720  * if it may be moved to a more global node?
13721  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13722  )
13723 {
13724  SCIP_CONSHDLR* conshdlr;
13725  SCIP_CONSDATA* consdata;
13726 
13727  assert(scip != NULL);
13728 
13729  /* find the cumulative constraint handler */
13730  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13731  if( conshdlr == NULL )
13732  {
13733  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13734  return SCIP_PLUGINNOTFOUND;
13735  }
13736 
13737  SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13738 
13739  /* create constraint data */
13740  SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13741 
13742  /* create constraint */
13743  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13744  initial, separate, enforce, check, propagate,
13745  local, modifiable, dynamic, removable, stickingatnode) );
13746 
13747  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13748  {
13749  SCIP_CONSHDLRDATA* conshdlrdata;
13750 
13751  /* get event handler */
13752  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13753  assert(conshdlrdata != NULL);
13754  assert(conshdlrdata->eventhdlr != NULL);
13755 
13756  /* catch bound change events of variables */
13757  SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13758  }
13759 
13760  return SCIP_OKAY;
13761 }
13762 
13763 /** creates and captures a cumulative constraint
13764  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13765  * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13766  *
13767  * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13768  *
13769  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13770  */
13772  SCIP* scip, /**< SCIP data structure */
13773  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13774  const char* name, /**< name of constraint */
13775  int nvars, /**< number of variables (jobs) */
13776  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13777  int* durations, /**< array containing corresponding durations */
13778  int* demands, /**< array containing corresponding demands */
13779  int capacity /**< available cumulative capacity */
13780  )
13781 {
13782  assert(scip != NULL);
13783 
13784  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13785  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13786 
13787  return SCIP_OKAY;
13788 }
13789 
13790 /** set the left bound of the time axis to be considered (including hmin) */ /*lint -e{715}*/
13792  SCIP* scip, /**< SCIP data structure */
13793  SCIP_CONS* cons, /**< constraint data */
13794  int hmin /**< left bound of time axis to be considered */
13795  )
13796 {
13797  SCIP_CONSDATA* consdata;
13798  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13799  {
13800  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13801  return SCIP_INVALIDCALL;
13802  }
13803 
13804  consdata = SCIPconsGetData(cons);
13805  assert(consdata != NULL);
13806  assert(hmin >= 0);
13807  assert(hmin <= consdata->hmax);
13808 
13809  consdata->hmin = hmin;
13810 
13811  return SCIP_OKAY;
13812 }
13813 
13814 /** returns the left bound of the time axis to be considered */ /*lint -e{715}*/
13816  SCIP* scip, /**< SCIP data structure */
13817  SCIP_CONS* cons /**< constraint */
13818  )
13819 {
13820  SCIP_CONSDATA* consdata;
13821  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13822  {
13823  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13824  SCIPABORT();
13825  return 0; /*lint !e527*/
13826  }
13827 
13828  consdata = SCIPconsGetData(cons);
13829  assert(consdata != NULL);
13830 
13831  return consdata->hmin;
13832 }
13833 
13834 /** set the right bound of the time axis to be considered (not including hmax) */ /*lint -e{715}*/
13836  SCIP* scip, /**< SCIP data structure */
13837  SCIP_CONS* cons, /**< constraint data */
13838  int hmax /**< right bound of time axis to be considered */
13839  )
13840 {
13841  SCIP_CONSDATA* consdata;
13842  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13843  {
13844  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13845  SCIPABORT();
13846  return SCIP_INVALIDCALL; /*lint !e527*/
13847  }
13848 
13849  consdata = SCIPconsGetData(cons);
13850  assert(consdata != NULL);
13851  assert(hmax >= consdata->hmin);
13852 
13853  consdata->hmax = hmax;
13854 
13855  return SCIP_OKAY;
13856 }
13857 
13858 /** returns the right bound of the time axis to be considered */ /*lint -e{715}*/
13860  SCIP* scip, /**< SCIP data structure */
13861  SCIP_CONS* cons /**< constraint */
13862  )
13863 {
13864  SCIP_CONSDATA* consdata;
13865  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13866  {
13867  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13868  SCIPABORT();
13869  return 0; /*lint !e527*/
13870  }
13871 
13872  consdata = SCIPconsGetData(cons);
13873  assert(consdata != NULL);
13874 
13875  return consdata->hmax;
13876 }
13877 
13878 /** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13880  SCIP* scip, /**< SCIP data structure */
13881  SCIP_CONS* cons /**< constraint data */
13882  )
13883 {
13884  SCIP_CONSDATA* consdata;
13885 
13886  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13887  {
13888  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13889  SCIPABORT();
13890  return NULL; /*lint !e527*/
13891  }
13892 
13893  consdata = SCIPconsGetData(cons);
13894  assert(consdata != NULL);
13895 
13896  return consdata->vars;
13897 }
13898 
13899 /** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13901  SCIP* scip, /**< SCIP data structure */
13902  SCIP_CONS* cons /**< constraint data */
13903  )
13904 {
13905  SCIP_CONSDATA* consdata;
13906 
13907  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13908  {
13909  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13910  SCIPABORT();
13911  return -1; /*lint !e527*/
13912  }
13913 
13914  consdata = SCIPconsGetData(cons);
13915  assert(consdata != NULL);
13916 
13917  return consdata->nvars;
13918 }
13919 
13920 /** returns the capacity of the cumulative constraint */ /*lint -e{715}*/
13922  SCIP* scip, /**< SCIP data structure */
13923  SCIP_CONS* cons /**< constraint data */
13924  )
13925 {
13926  SCIP_CONSDATA* consdata;
13927 
13928  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13929  {
13930  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13931  SCIPABORT();
13932  return -1; /*lint !e527*/
13933  }
13934 
13935  consdata = SCIPconsGetData(cons);
13936  assert(consdata != NULL);
13937 
13938  return consdata->capacity;
13939 }
13940 
13941 /** returns the durations of the cumulative constraint */ /*lint -e{715}*/
13943  SCIP* scip, /**< SCIP data structure */
13944  SCIP_CONS* cons /**< constraint data */
13945  )
13946 {
13947  SCIP_CONSDATA* consdata;
13948 
13949  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13950  {
13951  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13952  SCIPABORT();
13953  return NULL; /*lint !e527*/
13954  }
13955 
13956  consdata = SCIPconsGetData(cons);
13957  assert(consdata != NULL);
13958 
13959  return consdata->durations;
13960 }
13961 
13962 /** returns the demands of the cumulative constraint */ /*lint -e{715}*/
13964  SCIP* scip, /**< SCIP data structure */
13965  SCIP_CONS* cons /**< constraint data */
13966  )
13967 {
13968  SCIP_CONSDATA* consdata;
13969 
13970  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13971  {
13972  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13973  SCIPABORT();
13974  return NULL; /*lint !e527*/
13975  }
13976 
13977  consdata = SCIPconsGetData(cons);
13978  assert(consdata != NULL);
13979 
13980  return consdata->demands;
13981 }
13982 
13983 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
13984  * given solution is satisfied
13985  */
13987  SCIP* scip, /**< SCIP data structure */
13988  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
13989  int nvars, /**< number of variables (jobs) */
13990  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13991  int* durations, /**< array containing corresponding durations */
13992  int* demands, /**< array containing corresponding demands */
13993  int capacity, /**< available cumulative capacity */
13994  int hmin, /**< left bound of time axis to be considered (including hmin) */
13995  int hmax, /**< right bound of time axis to be considered (not including hmax) */
13996  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
13997  SCIP_CONS* cons, /**< constraint which is checked */
13998  SCIP_Bool printreason /**< should the reason for the violation be printed? */
13999  )
14000 {
14001  assert(scip != NULL);
14002  assert(violated != NULL);
14003 
14004  SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
14005  violated, cons, printreason) );
14006 
14007  return SCIP_OKAY;
14008 }
14009 
14010 /** normalize cumulative condition */ /*lint -e{715}*/
14012  SCIP* scip, /**< SCIP data structure */
14013  int nvars, /**< number of start time variables (activities) */
14014  SCIP_VAR** vars, /**< array of start time variables */
14015  int* durations, /**< array of durations */
14016  int* demands, /**< array of demands */
14017  int* capacity, /**< pointer to store the changed cumulative capacity */
14018  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
14019  int* nchgsides /**< pointer to count number of side changes */
14020  )
14021 { /*lint --e{715}*/
14022  normalizeCumulativeCondition(scip, nvars, demands, capacity, nchgcoefs, nchgsides);
14023 
14024  return SCIP_OKAY;
14025 }
14026 
14027 /** searches for a time point within the cumulative condition were the cumulative condition can be split */
14029  SCIP* scip, /**< SCIP data structure */
14030  int nvars, /**< number of variables (jobs) */
14031  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14032  int* durations, /**< array containing corresponding durations */
14033  int* demands, /**< array containing corresponding demands */
14034  int capacity, /**< available cumulative capacity */
14035  int* hmin, /**< pointer to store the left bound of the effective horizon */
14036  int* hmax, /**< pointer to store the right bound of the effective horizon */
14037  int* split /**< point were the cumulative condition can be split */
14038  )
14039 {
14040  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14041  hmin, hmax, split) );
14042 
14043  return SCIP_OKAY;
14044 }
14045 
14046 /** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
14048  SCIP* scip, /**< SCIP data structure */
14049  int nvars, /**< number of start time variables (activities) */
14050  SCIP_VAR** vars, /**< array of start time variables */
14051  int* durations, /**< array of durations */
14052  int hmin, /**< left bound of time axis to be considered */
14053  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14054  SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
14055  SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
14056  SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
14057  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
14058  int* nfixedvars, /**< pointer to store the number of fixed variables */
14059  int* nchgsides, /**< pointer to store the number of changed sides */
14060  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
14061  )
14062 {
14063  if( nvars <= 1 )
14064  return SCIP_OKAY;
14065 
14066  /* presolve constraint form the earlier start time point of view */
14067  SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14068  irrelevants, nfixedvars, nchgsides, cutoff) );
14069 
14070  /* presolve constraint form the latest completion time point of view */
14071  SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14072  irrelevants, nfixedvars, nchgsides, cutoff) );
14073 
14074  return SCIP_OKAY;
14075 }
14076 
14077 /** propagate the given cumulative condition */
14079  SCIP* scip, /**< SCIP data structure */
14080  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
14081  int nvars, /**< number of variables (jobs) */
14082  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14083  int* durations, /**< array containing corresponding durations */
14084  int* demands, /**< array containing corresponding demands */
14085  int capacity, /**< available cumulative capacity */
14086  int hmin, /**< left bound of time axis to be considered (including hmin) */
14087  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14088  SCIP_CONS* cons, /**< constraint which gets propagated */
14089  int* nchgbds, /**< pointer to store the number of variable bound changes */
14090  SCIP_Bool* initialized, /**< was conflict analysis initialized */
14091  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14092  SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14093  )
14094 {
14095  SCIP_CONSHDLR* conshdlr;
14096  SCIP_CONSHDLRDATA* conshdlrdata;
14097  SCIP_Bool redundant;
14098 
14099  assert(scip != NULL);
14100  assert(cons != NULL);
14101  assert(initialized != NULL);
14102  assert(*initialized == FALSE);
14103  assert(cutoff != NULL);
14104  assert(*cutoff == FALSE);
14105 
14106  /* find the cumulative constraint handler */
14107  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14108  if( conshdlr == NULL )
14109  {
14110  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14111  return SCIP_PLUGINNOTFOUND;
14112  }
14113 
14114  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14115  assert(conshdlrdata != NULL);
14116 
14117  redundant = FALSE;
14118 
14119  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14120  nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14121  nchgbds, &redundant, initialized, explanation, cutoff) );
14122 
14123  return SCIP_OKAY;
14124 }
14125 
14126 /** resolve propagation w.r.t. the cumulative condition */
14128  SCIP* scip, /**< SCIP data structure */
14129  int nvars, /**< number of start time variables (activities) */
14130  SCIP_VAR** vars, /**< array of start time variables */
14131  int* durations, /**< array of durations */
14132  int* demands, /**< array of demands */
14133  int capacity, /**< cumulative capacity */
14134  int hmin, /**< left bound of time axis to be considered (including hmin) */
14135  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14136  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14137  int inferinfo, /**< the user information */
14138  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14139  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14140  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14141  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14142  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14143  )
14144 {
14145  SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14146  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14147 
14148  return SCIP_OKAY;
14149 }
14150 
14151 /** this method visualizes the cumulative structure in GML format */
14153  SCIP* scip, /**< SCIP data structure */
14154  SCIP_CONS* cons /**< cumulative constraint */
14155  )
14156 {
14157  SCIP_CONSDATA* consdata;
14158  SCIP_HASHTABLE* vars;
14159  FILE* file;
14160  SCIP_VAR* var;
14161  char filename[SCIP_MAXSTRLEN];
14162  int nvars;
14163  int v;
14164 
14165  SCIP_RETCODE retcode = SCIP_OKAY;
14166 
14167  /* open file */
14168  (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14169  file = fopen(filename, "w");
14170 
14171  /* check if the file was open */
14172  if( file == NULL )
14173  {
14174  SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14175  SCIPprintSysError(filename);
14176  return SCIP_FILECREATEERROR;
14177  }
14178 
14179  consdata = SCIPconsGetData(cons);
14180  assert(consdata != NULL);
14181 
14182  nvars = consdata->nvars;
14183 
14184  SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
14185  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
14186 
14187  /* create opening of the GML format */
14188  SCIPgmlWriteOpening(file, TRUE);
14189 
14190  for( v = 0; v < nvars; ++v )
14191  {
14192  char color[SCIP_MAXSTRLEN];
14193 
14194  var = consdata->vars[v];
14195  assert(var != NULL);
14196 
14197  SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
14198 
14199  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14200  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14201  else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14202  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14203  else
14204  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14205 
14206  SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14207  }
14208 
14209  for( v = 0; v < nvars; ++v )
14210  {
14211  SCIP_VAR** vbdvars;
14212  int nvbdvars;
14213  int b;
14214 
14215  var = consdata->vars[v];
14216  assert(var != NULL);
14217 
14218  vbdvars = SCIPvarGetVlbVars(var);
14219  nvbdvars = SCIPvarGetNVlbs(var);
14220 
14221  for( b = 0; b < nvbdvars; ++b )
14222  {
14223  if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14224  {
14225  SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14226  }
14227  }
14228 
14229 #if 0
14230  vbdvars = SCIPvarGetVubVars(var);
14231  nvbdvars = SCIPvarGetNVubs(var);
14232 
14233  for( b = 0; b < nvbdvars; ++b )
14234  {
14235  if( SCIPhashtableExists(vars, vbdvars[b]) )
14236  {
14237  SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14238  }
14239  }
14240 #endif
14241  }
14242 
14243  /* create closing of the GML format */
14244  SCIPgmlWriteClosing(file);
14245 TERMINATE:
14246  /* close file */
14247  fclose(file);
14248 
14249  SCIPhashtableFree(&vars);
14250 
14251  return retcode;
14252 }
14253 
14254 /** sets method to solve an individual cumulative condition */
14256  SCIP* scip, /**< SCIP data structure */
14257  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14258  )
14259 {
14260  SCIP_CONSHDLR* conshdlr;
14261  SCIP_CONSHDLRDATA* conshdlrdata;
14262 
14263  /* find the cumulative constraint handler */
14264  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14265  if( conshdlr == NULL )
14266  {
14267  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14268  return SCIP_PLUGINNOTFOUND;
14269  }
14270 
14271  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14272  assert(conshdlrdata != NULL);
14273 
14274  conshdlrdata->solveCumulative = solveCumulative;
14275 
14276  return SCIP_OKAY;
14277 }
14278 
14279 /** solves given cumulative condition as independent sub problem
14280  *
14281  * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14282  * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14283  * solver was interrupted.
14284  */
14286  SCIP* scip, /**< SCIP data structure */
14287  int njobs, /**< number of jobs (activities) */
14288  SCIP_Real* ests, /**< array with the earlier start time for each job */
14289  SCIP_Real* lsts, /**< array with the latest start time for each job */
14290  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14291  int* durations, /**< array of durations */
14292  int* demands, /**< array of demands */
14293  int capacity, /**< cumulative capacity */
14294  int hmin, /**< left bound of time axis to be considered (including hmin) */
14295  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14296  SCIP_Real timelimit, /**< time limit for solving in seconds */
14297  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14298  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14299  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14300  SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14301  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14302  SCIP_Bool* error /**< pointer to store if an error occurred */
14303  )
14304 {
14305  SCIP_CONSHDLR* conshdlr;
14306  SCIP_CONSHDLRDATA* conshdlrdata;
14307 
14308  (*solved) = TRUE;
14309  (*infeasible) = FALSE;
14310  (*unbounded) = FALSE;
14311  (*error) = FALSE;
14312 
14313  if( njobs == 0 )
14314  return SCIP_OKAY;
14315 
14316  /* find the cumulative constraint handler */
14317  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14318  if( conshdlr == NULL )
14319  {
14320  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14321  (*error) = TRUE;
14322  return SCIP_PLUGINNOTFOUND;
14323  }
14324 
14325  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14326  assert(conshdlrdata != NULL);
14327 
14328  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14329  if( timelimit > 0.0 && memorylimit > 10 )
14330  {
14331  SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14332  hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14333  }
14334 
14335  return SCIP_OKAY;
14336 }
14337 
14338 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14339  * completion time
14340  */
14342  SCIP* scip, /**< SCIP data structure */
14343  SCIP_PROFILE* profile, /**< resource profile */
14344  int nvars, /**< number of variables (jobs) */
14345  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14346  int* durations, /**< array containing corresponding durations */
14347  int* demands /**< array containing corresponding demands */
14348  )
14349 {
14350  SCIP_VAR* var;
14351  SCIP_HASHMAP* addedvars;
14352  int* copydemands;
14353  int* perm;
14354  int duration;
14355  int impliedest;
14356  int est;
14357  int impliedlct;
14358  int lct;
14359  int v;
14360 
14361  /* create hash map for variables which are added, mapping to their duration */
14362  SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
14363 
14364  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14365  SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14366 
14367  /* sort variables w.r.t. job demands */
14368  for( v = 0; v < nvars; ++v )
14369  {
14370  copydemands[v] = demands[v];
14371  perm[v] = v;
14372  }
14373  SCIPsortDownIntInt(copydemands, perm, nvars);
14374 
14375  /* add each job with its earliest start and latest completion time into the resource profile */
14376  for( v = 0; v < nvars; ++v )
14377  {
14378  int idx;
14379 
14380  idx = perm[v];
14381  assert(idx >= 0 && idx < nvars);
14382 
14383  var = vars[idx];
14384  assert(var != NULL);
14385 
14386  duration = durations[idx];
14387  assert(duration > 0);
14388 
14389  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
14390  SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14391 
14392  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14393  SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14394 
14395  if( impliedest < impliedlct )
14396  {
14397  SCIP_Bool infeasible;
14398  int pos;
14399 
14400  SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14401  assert(!infeasible);
14402  assert(pos == -1);
14403  }
14404 
14405  if( est == impliedest && lct == impliedlct )
14406  {
14407  SCIP_CALL( SCIPhashmapInsertInt(addedvars, (void*)var, duration) );
14408  }
14409  }
14410 
14411  SCIPfreeBufferArray(scip, &copydemands);
14412  SCIPfreeBufferArray(scip, &perm);
14413 
14414  SCIPhashmapFree(&addedvars);
14415 
14416  return SCIP_OKAY;
14417 }
14418 
14419 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */ /*lint -e{715}*/
14420 int SCIPcomputeHmin(
14421  SCIP* scip, /**< SCIP data structure */
14422  SCIP_PROFILE* profile, /**< worst case resource profile */
14423  int capacity /**< capacity to check */
14424  )
14425 {
14426  int* timepoints;
14427  int* loads;
14428  int ntimepoints;
14429  int t;
14430 
14431  ntimepoints = SCIPprofileGetNTimepoints(profile);
14432  timepoints = SCIPprofileGetTimepoints(profile);
14433  loads = SCIPprofileGetLoads(profile);
14434 
14435  /* find first time point which potentially violates the capacity restriction */
14436  for( t = 0; t < ntimepoints - 1; ++t )
14437  {
14438  /* check if the time point exceed w.r.t. worst case profile the capacity */
14439  if( loads[t] > capacity )
14440  {
14441  assert(t == 0 || loads[t-1] <= capacity);
14442  return timepoints[t];
14443  }
14444  }
14445 
14446  return INT_MAX;
14447 }
14448 
14449 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity is satisfied for sure */ /*lint -e{715}*/
14450 int SCIPcomputeHmax(
14451  SCIP* scip, /**< SCIP data structure */
14452  SCIP_PROFILE* profile, /**< worst case profile */
14453  int capacity /**< capacity to check */
14454  )
14455 {
14456  int* timepoints;
14457  int* loads;
14458  int ntimepoints;
14459  int t;
14460 
14461  ntimepoints = SCIPprofileGetNTimepoints(profile);
14462  timepoints = SCIPprofileGetTimepoints(profile);
14463  loads = SCIPprofileGetLoads(profile);
14464 
14465  /* find last time point which potentially violates the capacity restriction */
14466  for( t = ntimepoints - 1; t >= 0; --t )
14467  {
14468  /* check if at time point t the worst case resource profile exceeds the capacity */
14469  if( loads[t] > capacity )
14470  {
14471  assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14472  return timepoints[t+1];
14473  }
14474  }
14475 
14476  return INT_MIN;
14477 }
14478 
14479 /**@} */
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
static SCIP_RETCODE consdataCatchEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
#define CONSHDLR_SEPAPRIORITY
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4209
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:86
SCIP_RETCODE SCIPcreateConsBasicSetpart(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
Definition: cons_setppc.c:9095
SCIP_BTNODE * SCIPbtnodeGetRightchild(SCIP_BTNODE *node)
Definition: misc.c:8703
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_EXPORT SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17159
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
static SCIP_DECL_CONSCOPY(consCopyCumulative)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:687
enum TCLIQUE_Status TCLIQUE_STATUS
Definition: tclique.h:59
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:586
static TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
#define DEFAULT_TTINFER
#define CONSHDLR_PROPFREQ
static int computeEnergyContribution(SCIP_BTNODE *node)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:80
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2486
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip_branch.c:656
static SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:877
static SCIP_RETCODE consdataDropAllEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static PROPRULE inferInfoGetProprule(INFERINFO inferinfo)
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:1996
static SCIP_RETCODE checkCumulativeCondition(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *violated, SCIP_CONS *cons, SCIP_Bool printreason)
constraint handler for cumulative constraints
static SCIP_RETCODE propagateEdgeFinding(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:453
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5184
static SCIP_RETCODE computeMinDistance(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int source, int sink, int *naddconss)
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:934
SCIP_RETCODE SCIPaddVarVlb(SCIP *scip, SCIP_VAR *var, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconstant, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip_var.c:6642
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8328
struct TCLIQUE_Graph TCLIQUE_GRAPH
Definition: tclique.h:40
static INFERINFO intToInferInfo(int i)
SCIP_EXPORT int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3250
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:308
SCIP_BTNODE * SCIPbtnodeGetLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8693
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:467
int SCIPprofileGetLoad(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6750
static void consdataPrint(SCIP *scip, SCIP_CONSDATA *consdata, FILE *file)
static SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
static SCIP_RETCODE analyzeConflictOverload(SCIP *scip, SCIP_BTNODE **leaves, int capacity, int nleaves, int est, int lct, int reportedenergy, SCIP_Bool propest, int shift, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation)
static SCIP_RETCODE createCoverCutsTimepoint(SCIP *scip, SCIP_CONS *cons, int *startvalues, int time)
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8288
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:166
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4263
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2598
static void addEndingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *endtimes, int *endindices, int *freecapacity, int *idx, int nvars)
#define SCIP_MAXSTRLEN
Definition: def.h:273
#define DEFAULT_MAXNODES
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:1484
SCIP_RETCODE SCIPcreateConsBasicCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity)
SCIP_RETCODE SCIPnormalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
int SCIPgetHminCumulative(SCIP *scip, SCIP_CONS *cons)
static int computeOverlap(int begin, int end, int est, int lst, int duration)
static SCIP_RETCODE constraintNonOverlappingGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:816
static void normalizeCumulativeCondition(SCIP *scip, int nvars, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
static long bound
SCIP_EXPORT void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
static SCIP_RETCODE analyzeEnergyRequirement(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int begin, int end, SCIP_VAR *infervar, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation)
static void initializeLocks(SCIP_CONSDATA *consdata, SCIP_Bool locked)
#define CONSHDLR_NAME
#define SCIP_CALL_FINALLY(x, y)
Definition: def.h:406
SCIP_VAR ** SCIPgetVarsCumulative(SCIP *scip, SCIP_CONS *cons)
#define CONSHDLR_PROP_TIMING
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1353
SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_setppc.c:9226
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5301
static SCIP_RETCODE createDisjuctiveCons(SCIP *scip, SCIP_CONS *cons, int *naddconss)
#define CONSHDLR_CHECKPRIORITY
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2152
static int inferInfoGetData1(INFERINFO inferinfo)
static SCIP_RETCODE solveIndependentCons(SCIP *scip, SCIP_CONS *cons, SCIP_Longint maxnodes, int *nchgbds, int *nfixedvars, int *ndelconss, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
static void updateKeyOnTrace(SCIP_BTNODE *node, SCIP_Real key)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:9008
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:770
static SCIP_RETCODE presolveConsEst(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
SCIP_Bool SCIPbtnodeIsLeaf(SCIP_BTNODE *node)
Definition: misc.c:8743
static SCIP_RETCODE computePeak(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *timepoint)
SCIP_BTNODE * SCIPbtnodeGetParent(SCIP_BTNODE *node)
Definition: misc.c:8683
static SCIP_Longint computeCoreWithInterval(int begin, int end, int ect, int lst)
static void transitiveClosure(SCIP_Bool **adjmatrix, int *ninarcs, int *noutarcs, int nnodes)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5596
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition: scip_var.c:185
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3131
SCIP_RETCODE SCIPbtCreate(SCIP_BT **tree, BMS_BLKMEM *blkmem)
Definition: misc.c:8845
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:315
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3036
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1986
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8150
static SCIP_RETCODE applyAlternativeBoundsFixing(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, int *nfixedvars, SCIP_Bool *cutoff)
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:360
static SCIP_DECL_SORTPTRCOMP(compNodeEst)
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1368
#define FALSE
Definition: def.h:73
void SCIPstrCopySection(const char *str, char startchar, char endchar, char *token, int size, char **endptr)
Definition: misc.c:10721
static SCIP_RETCODE collectIntVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***activevars, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower, int *lhs)
static SCIP_RETCODE fixIntegerVariableLb(SCIP *scip, SCIP_VAR *var, SCIP_Bool downlock, int *nfixedvars)
SCIP_EXPORT SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17515
static SCIP_RETCODE consdataFreeRows(SCIP *scip, SCIP_CONSDATA **consdata)
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_RETCODE checkOverloadViaThetaTree(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool propest, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPcreateConsLinking(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *linkvar, SCIP_VAR **binvars, SCIP_Real *vals, int nbinvars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_EXPORT SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17182
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:72
#define SCIPdebug(x)
Definition: pub_message.h:84
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
static SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
enum Proprule PROPRULE
static void subtractStartingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *starttimes, int *startindices, int *freecapacity, int *idx, int nvars)
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3468
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:524
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8258
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
static SCIP_RETCODE presolveConsEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff)
static SCIP_RETCODE removeIrrelevantJobs(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE applyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_Real leftub, SCIP_Real rightlb, SCIP_Real *leftimpllbs, SCIP_Real *leftimplubs, SCIP_Real *leftproplbs, SCIP_Real *leftpropubs, SCIP_Real *rightimpllbs, SCIP_Real *rightimplubs, SCIP_Real *rightproplbs, SCIP_Real *rightpropubs, int *nfixedvars, SCIP_Bool *success, SCIP_Bool *cutoff)
static SCIP_RETCODE presolveCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nfixedvars, int *nchgbds, int *ndelconss, int *naddconss, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
static SCIP_RETCODE strengthenVarbounds(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *naddconss)
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:563
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2527
static SCIP_RETCODE getNodeIdx(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_VAR *var, int *idx)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3200
SCIP_EXPORT SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17340
static void conshdlrdataFree(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata)
#define DEFAULT_LOCALCUTS
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:48
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:95
SCIP_Longint SCIPgetMemUsed(SCIP *scip)
Definition: scip_mem.c:91
static SCIP_RETCODE deleteLambdaLeaf(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
#define SCIPdebugMessage
Definition: pub_message.h:87
#define CONSHDLR_DELAYPROP
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1604
static SCIP_RETCODE separateCoverCutsCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
#define DEFAULT_USEBINVARS
SCIP_EXPORT SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17136
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip_cons.c:1233
SCIP_RETCODE SCIPsetSubscipsOff(SCIP *scip, SCIP_Bool quiet)
Definition: scip_param.c:893
static TCLIQUE_ISEDGE(tcliqueIsedgeClique)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:119
tclique user interface
static SCIP_RETCODE createCoreProfile(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
#define DEFAULT_COEFTIGHTENING
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:525
static SCIP_RETCODE createNodedata(SCIP *scip, SCIP_NODEDATA **nodedata)
static void normalizeDemands(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
#define SCIP_LONGINT_MAX
Definition: def.h:149
SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:123
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:136
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip_cons.c:1258
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:839
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:78
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:93
#define DEFAULT_TTEFCHECK
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
static void createSelectedSortedEventpointsSol(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *starttimes, int *endtimes, int *startindices, int *endindices, int *nvars, SCIP_Bool lower)
static SCIP_DECL_CONSINITLP(consInitlpCumulative)
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:501
SCIP_RETCODE SCIPsetHmaxCumulative(SCIP *scip, SCIP_CONS *cons, int hmax)
static SCIP_RETCODE propagateAllConss(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *nfixedvars, SCIP_Bool *cutoff, SCIP_Bool *branched)
#define SCIPdebugMsg
Definition: scip_message.h:69
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2107
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
void SCIPprofilePrint(SCIP_PROFILE *profile, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: misc.c:6676
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4354
SCIP_EXPORT void SCIPsortInt(int *intarray, int len)
static SCIP_DECL_CONSPRESOL(consPresolCumulative)
SCIP_EXPORT SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17871
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:559
#define DEFAULT_NORMALIZE
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
static SCIP_RETCODE deleteTrivilCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:357
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip_cons.c:1461
static SCIP_RETCODE respropCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, INFERINFO inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation, SCIP_RESULT *result)
static SCIP_RETCODE removeOversizedJobs(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *nchgcoefs, int *naddconss, SCIP_Bool *cutoff)
void * SCIPbtnodeGetData(SCIP_BTNODE *node)
Definition: misc.c:8673
static SCIP_RETCODE createConsCumulative(SCIP *scip, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
enum Proprule PROPRULE
static SCIP_RETCODE adjustOversizedJobBounds(SCIP *scip, SCIP_CONSDATA *consdata, int pos, int *nchgbds, int *naddconss, SCIP_Bool *cutoff)
SCIP_Bool SCIPbtnodeIsLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8753
void SCIPgmlWriteOpening(FILE *file, SCIP_Bool directed)
Definition: misc.c:672
void SCIPgmlWriteArc(FILE *file, unsigned int source, unsigned int target, const char *label, const char *color)
Definition: misc.c:628
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:2235
static SCIP_Bool isConsIndependently(SCIP_CONS *cons)
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:265
static SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
static SCIP_RETCODE coretimesUpdateUb(SCIP *scip, SCIP_VAR *var, int duration, int demand, int capacity, SCIP_CONS *cons, SCIP_PROFILE *profile, int idx, int *nchgbds)
SCIP_RETCODE SCIPcreateConsVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static void freeTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
#define CONSHDLR_DESC
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2837
static void createSortedEventpointsSol(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices)
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17372
int SCIPgetNVarsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE conshdlrdataCreate(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition: scip_param.c:613
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3220
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip_copy.c:697
SCIP_RETCODE SCIPsplitCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
static SCIP_RETCODE enforceSolution(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool branch, SCIP_RESULT *result)
SCIP_EXPORT SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:17218
static SCIP_RETCODE separateConsBinaryRepresentation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
static SCIP_RETCODE findPrecedenceConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
static SCIP_DECL_CONSCHECK(consCheckCumulative)
static SCIP_Longint computeTotalEnergy(int *durations, int *demands, int njobs)
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3362
static SCIP_RETCODE tightenLbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int ect, int lct, int begin, int end, SCIP_Longint energy, int *bestlb, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_RETCODE getHighestCapacityUsage(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, int *bestcapacity)
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:92
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8648
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_VAR **vars, SCIP_CONS **linkingconss, int *durations, int *demands, int nvars, int capacity, int hmin, int hmax, SCIP_Bool check)
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip_general.c:283
int SCIPprofileGetNTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6708
Constraint handler for knapsack constraints of the form , x binary and .
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10898
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1581
static const NodeData nodedata[]
Definition: gastrans.c:74
int SCIPcomputeHmin(SCIP *scip, SCIP_PROFILE *profile, int capacity)
#define CONSHDLR_EAGERFREQ
#define CONSHDLR_PRESOLTIMING
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
SCIP_EXPORT const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17017
static SCIP_RETCODE collectBranchingCands(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nbranchcands)
#define CONSHDLR_DELAYSEPA
static SCIP_RETCODE findCumulativeConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
static int inferInfoGetData2(INFERINFO inferinfo)
#define EVENTHDLR_NAME
static SCIP_RETCODE propagateTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_DECL_CONSLOCK(consLockCumulative)
SCIP_RETCODE SCIPapplyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_BOUNDTYPE boundtype, SCIP_Real bound, int maxproprounds, SCIP_Real *impllbs, SCIP_Real *implubs, SCIP_Real *proplbs, SCIP_Real *propubs, SCIP_Bool *cutoff)
SCIP_CONS * SCIPgetConsLinking(SCIP *scip, SCIP_VAR *linkvar)
#define SCIPerrorMessage
Definition: pub_message.h:55
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10691
static SCIP_RETCODE projectVbd(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph)
static SCIP_RETCODE createTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
SCIP_RETCODE SCIPsolveCumulative(SCIP *scip, int njobs, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Real *objvals, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Longint maxnodes, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *error)
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1508
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE collectBinaryVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***vars, int **coefs, int *nvars, int *startindices, int curtime, int nstarted, int nfinished)
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1941
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:109
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
int SCIPgetHmaxCumulative(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:124
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:48
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
static void traceLambdaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
SCIP_EXPORT SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17923
SCIP_EXPORT void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
static SCIP_RETCODE computeEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss, int *nchgsides)
static int computeEstOmegaset(SCIP *scip, int duration, int demand, int capacity, int est, int lct, int energy)
void SCIPbtnodeFree(SCIP_BT *tree, SCIP_BTNODE **node)
Definition: misc.c:8628
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
static SCIP_RETCODE branch(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_RESULT *result)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:164
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:88
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:155
static TCLIQUE_NEWSOL(tcliqueNewsolClique)
static SCIP_RETCODE coretimesUpdateLb(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_PROFILE *profile, int idx, int *nchgbds, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *infeasible)
static SCIP_RETCODE createCumulativeCons(SCIP *scip, const char *name, TCLIQUE_GRAPH *tcliquegraph, int *cliquenodes, int ncliquenodes)
SCIP_RETCODE SCIPincludeConshdlrCumulative(SCIP *scip)
#define CONSHDLR_MAXPREROUNDS
static SCIP_RETCODE createCoverCuts(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:477
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss, SCIP_Bool *infeasible)
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8119
static SCIP_RETCODE solveCumulative(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool local, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Longint maxnodes, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *error)
#define SCIP_CALL(x)
Definition: def.h:364
SCIP_EXPORT int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17901
void SCIPswapInts(int *value1, int *value2)
Definition: misc.c:10192
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:632
static SCIP_RETCODE propagateLbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, int *newlbs, int *newubs, int *lbinferinfos, int *ubinferinfos, int *ects, int *flexenergies, int *perm, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static void updateEnvelope(SCIP *scip, SCIP_BTNODE *node)
SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1082
SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
Definition: scip_param.c:671
#define SCIPstatisticPrintf
Definition: pub_message.h:117
static TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
Definition: grphload.c:88
#define DEFAULT_PRESOLPAIRWISE
#define DEFAULT_DETECTDISJUNCTIVE
static SCIP_DECL_CONSFREE(consFreeCumulative)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:56
SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1075
SCIP_EXPORT void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:114
static SCIP_RETCODE consCapacityConstraintsFinder(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
static void collectDataTTEF(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int hmin, int hmax, int *permests, int *ests, int *permlcts, int *lcts, int *ects, int *lsts, int *flexenergies)
static SCIP_RETCODE consCheckRedundancy(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *redundant)
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1749
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip_param.c:298
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8358
constraint handler for linking binary variables to a linking (continuous or integer) variable ...
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:111
#define SCIP_UNKNOWN
Definition: def.h:184
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:130
SCIP_Real SCIPinfinity(SCIP *scip)
static SCIP_RETCODE propagateUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, int *newlbs, int *newubs, int *lbinferinfos, int *ubinferinfos, int *lsts, int *flexenergies, int *perm, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip_cons.c:220
static void traceThetaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4439
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2285
SCIP_EXPORT void SCIPsortDownIntIntInt(int *intarray1, int *intarray2, int *intarray3, int len)
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:638
#define SCIP_Bool
Definition: def.h:70
static SCIP_RETCODE presolveConsLct(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPincludeDefaultPlugins(SCIP *scip)
static SCIP_RETCODE consdataDropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos)
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:391
static SCIP_DECL_CONSPROP(consPropCumulative)
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1208
#define DEFAULT_DUALPRESOLVE
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3013
SCIP_Bool SCIPbtnodeIsRoot(SCIP_BTNODE *node)
Definition: misc.c:8733
SCIP_EXPORT void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
static SCIP_RETCODE analyseInfeasibelCoreInsertion(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferduration, int inferdemand, int inferpeak, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation)
#define DEFAULT_USEADJUSTEDJOBS
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nchgbds, int *ndelconss, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:332
int SCIPgetNCheckConss(SCIP *scip)
Definition: scip_prob.c:3178
SCIP_EXPORT SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17677
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2473
#define DEFAULT_USECOVERCUTS
SCIP_RETCODE SCIPprofileDeleteCore(SCIP_PROFILE *profile, int left, int right, int demand)
Definition: misc.c:6941
static void freeNodedata(SCIP *scip, SCIP_NODEDATA **nodedata)
static SCIP_DECL_EVENTEXEC(eventExecCumulative)
int SCIPprofileGetTime(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6738
void SCIPbtSetRoot(SCIP_BT *tree, SCIP_BTNODE *root)
Definition: misc.c:8969
SCIP_Bool SCIPprofileFindLeft(SCIP_PROFILE *profile, int timepoint, int *pos)
Definition: misc.c:6764
#define SCIP_DECL_CONSEXITPRE(x)
Definition: type_cons.h:170
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:91
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4199
#define MAX(x, y)
Definition: tclique_def.h:83
SCIP_RETCODE SCIPsetEmphasis(SCIP *scip, SCIP_PARAMEMPHASIS paramemphasis, SCIP_Bool quiet)
Definition: scip_param.c:871
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip_var.c:105
SCIP_RETCODE SCIPcheckCumulativeCondition(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *violated, SCIP_CONS *cons, SCIP_Bool printreason)
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
void SCIPgmlWriteClosing(FILE *file)
Definition: misc.c:688
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5439
SCIP_Bool SCIPexistsConsLinking(SCIP *scip, SCIP_VAR *linkvar)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8398
SCIP_RETCODE SCIPbtnodeCreate(SCIP_BT *tree, SCIP_BTNODE **node, void *dataptr)
Definition: misc.c:8564
SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
SCIP_Bool SCIPbtIsEmpty(SCIP_BT *tree)
Definition: misc.c:8946
#define SCIP_PRESOLTIMING_ALWAYS
Definition: type_timing.h:49
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:126
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8268
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8255
int * SCIPprofileGetLoads(SCIP_PROFILE *profile)
Definition: misc.c:6728
SCIP_BTNODE * SCIPbtGetRoot(SCIP_BT *tree)
Definition: misc.c:8956
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)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
static SCIP_RETCODE consdataDeletePos(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_CONS *cons, int pos)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1666
#define CONSHDLR_NEEDSCONS
static SCIP_RETCODE computeImpliedEst(SCIP *scip, SCIP_VAR *var, SCIP_HASHMAP *addedvars, int *est)
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8348
static SCIP_RETCODE tightenCoefs(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs)
static SCIP_DECL_SORTINDCOMP(consdataCompVar)
Proprule
SCIP_EXPORT SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17723
#define DEFAULT_FILLBRANCHCANDS
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:95
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:10218
static SCIP_Bool checkDemands(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2132
SCIP_EXPORT int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3193
#define DEFAULT_DETECTVARBOUNDS
static SCIP_RETCODE tightenUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int lst, int lct, int begin, int end, SCIP_Longint energy, int *bestub, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPrespropCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool *explanation, SCIP_RESULT *result)
static SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
int SCIPconvertRealToInt(SCIP *scip, SCIP_Real real)
static SCIP_RETCODE setupAndSolveCumulativeSubscip(SCIP *subscip, SCIP_Real *objvals, int *durations, int *demands, int njobs, int capacity, int hmin, int hmax, SCIP_Longint maxnodes, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *solved, SCIP_Bool *error)
SCIP_Real * r
Definition: circlepacking.c:50
SCIP_RETCODE SCIPpresolveCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
SCIP_EXPORT SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17733
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip_param.c:555
static void createSortedEventpoints(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices, SCIP_Bool local)
SCIP_VAR ** b
Definition: circlepacking.c:56
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:221
SCIP_RETCODE SCIPsetHminCumulative(SCIP *scip, SCIP_CONS *cons, int hmin)
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5482
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:121
static SCIP_RETCODE insertThetanode(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node, SCIP_NODEDATA **nodedatas, int *nnodedatas)
#define CONSHDLR_SEPAFREQ
int SCIPgetCapacityCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE removeRedundantConss(SCIP *scip, SCIP_CONS **conss, int nconss, int *ndelconss)
static SCIP_RETCODE getActiveVar(SCIP *scip, SCIP_VAR **var, int *scalar, int *constant)
static SCIP_RETCODE computeAlternativeBounds(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks)
static void traceLambdaEnergy(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
static SCIP_DECL_CONSPRINT(consPrintCumulative)
static SCIP_RETCODE consdataCollectLinkingCons(SCIP *scip, SCIP_CONSDATA *consdata)
static SCIP_RETCODE initializeDurations(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8278
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnvelop(SCIP_BTNODE *node)
SCIP_RETCODE SCIPtransformConss(SCIP *scip, int nconss, SCIP_CONS **conss, SCIP_CONS **transconss)
Definition: scip_cons.c:1562
int * SCIPprofileGetTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6718
void SCIPbtnodeSetParent(SCIP_BTNODE *node, SCIP_BTNODE *parent)
Definition: misc.c:8806
static SCIP_RETCODE constructIncompatibilityGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
SCIP_EXPORT SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17667
static SCIP_RETCODE moveNodeToLambda(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
SCIP_EXPORT SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17881
#define DEFAULT_CUTSASCONSS
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1641
static void collectThetaSubtree(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
static void collectDemands(SCIP *scip, SCIP_CONSDATA *consdata, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Longint **demands, int *ndemands)
static SCIP_RETCODE separateConsOnIntegerVariables(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool lower, SCIP_Bool *separated, SCIP_Bool *cutoff)
void SCIPbtnodeSetLeftchild(SCIP_BTNODE *node, SCIP_BTNODE *left)
Definition: misc.c:8820
void SCIPprofileFree(SCIP_PROFILE **profile)
Definition: misc.c:6660
SCIP_EXPORT void tcliqueMaxClique(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, TCLIQUE_WEIGHT maxfirstnodeweight, TCLIQUE_WEIGHT minweight, int maxntreenodes, int backtrackfreq, int maxnzeroextensions, int fixednode, int *ntreenodes, TCLIQUE_STATUS *status)
SCIP_EXPORT SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17891
static SCIP_RETCODE resolvePropagationCoretimes(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferdemand, int inferpeak, int relaxedpeak, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool usebdwidening, int *provedpeak, SCIP_Bool *explanation)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10590
void SCIPbtnodeSetRightchild(SCIP_BTNODE *node, SCIP_BTNODE *right)
Definition: misc.c:8834
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3047
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8089
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1252
SCIP_RETCODE SCIPcreateWorstCaseProfile(SCIP *scip, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands)
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8218
#define SCIPstatistic(x)
Definition: pub_message.h:111
int * SCIPgetDemandsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
#define SCIP_Real
Definition: def.h:163
static SCIP_RETCODE applyAlternativeBoundsBranching(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, SCIP_Bool *branched)
static SCIP_DECL_CONSPARSE(consParseCumulative)
static SCIP_DECL_CONSTRANS(consTransCumulative)
static SCIP_RETCODE propagateTimetable(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
#define SCIP_CALL_TERMINATE(retcode, x, TERM)
Definition: def.h:385
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8109
SCIP_Bool SCIPbtnodeIsRightchild(SCIP_BTNODE *node)
Definition: misc.c:8771
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
static SCIP_RETCODE fixIntegerVariableUb(SCIP *scip, SCIP_VAR *var, SCIP_Bool uplock, int *nfixedvars)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define DEFAULT_EFCHECK
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIP_INVALID
Definition: def.h:183
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1950
#define EVENTHDLR_DESC
#define DEFAULT_TTEFINFER
void SCIPprintSysError(const char *message)
Definition: misc.c:10499
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:148
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition: scip_param.c:439
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8368
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4179
static SCIP_RETCODE detectRedundantConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, int *naddconss)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip_var.c:1798
static SCIP_RETCODE varMayRoundUp(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:345
SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:102
SCIP_EXPORT int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17360
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2764
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:55
SCIP_RETCODE SCIPcreateConsCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static void consdataCalcSignature(SCIP_CONSDATA *consdata)
#define DEFAULT_EFINFER
#define nnodes
Definition: gastrans.c:65
static SCIP_RETCODE createCapacityRestriction(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool cutsasconss)
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:98
SCIP_RETCODE SCIPpropCumulativeCondition(SCIP *scip, SCIP_PRESOLTIMING presoltiming, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
static SCIP_Bool impliesVlbPrecedenceCondition(SCIP *scip, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconst, int duration)
#define DEFAULT_DISJUNCTIVE
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8595
int SCIPcomputeHmax(SCIP *scip, SCIP_PROFILE *profile, int capacity)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:122
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
#define DEFAULT_USEBDWIDENING
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:315
SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
Definition: scip_mem.c:117
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:199
static SCIP_RETCODE tightenCapacity(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
static SCIP_RETCODE computeEffectiveHorizonCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1110
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition: scip_var.c:8380
void SCIPgmlWriteNode(FILE *file, unsigned int id, const char *label, const char *nodetype, const char *fillcolor, const char *bordercolor)
Definition: misc.c:486
int TCLIQUE_WEIGHT
Definition: tclique.h:39
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:356
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:793
static SCIP_DECL_CONSINITPRE(consInitpreCumulative)
static SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
static SCIP_RETCODE computeImpliedLct(SCIP *scip, SCIP_VAR *var, int duration, SCIP_HASHMAP *addedvars, int *lct)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:266
SCIP_EXPORT SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:17228
#define SCIPABORT()
Definition: def.h:336
SCIP_Real * SCIPgetValsLinking(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSDELETE(consDeleteCumulative)
void SCIPbtFree(SCIP_BT **tree)
Definition: misc.c:8864
SCIP_RETCODE SCIPvisualizeConsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPORT SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17933
default SCIP plugins
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnergy(SCIP_BTNODE *node)
SCIP_RETCODE SCIPprofileInsertCore(SCIP_PROFILE *profile, int left, int right, int demand, int *pos, SCIP_Bool *infeasible)
Definition: misc.c:6911
static SCIP_DECL_CONSSEPALP(consSepalpCumulative)
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2305
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8308
SCIP_EXPORT SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17913
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *violated, SCIP_Bool printreason)
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3378
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip_param.c:497
SCIP_RETCODE SCIPprofileCreate(SCIP_PROFILE **profile, int capacity)
Definition: misc.c:6646
static SCIP_RETCODE createCapacityRestrictionIntvars(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
Definition: scip_prob.c:170
SCIP_RETCODE SCIPgetBinvarsLinking(SCIP *scip, SCIP_CONS *cons, SCIP_VAR ***binvars, int *nbinvars)
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:609
static int inferInfoToInt(INFERINFO inferinfo)
static void computeCoreEnergyAfter(SCIP_PROFILE *profile, int nvars, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct)
static TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
SCIP_RETCODE SCIPsetSolveCumulative(SCIP *scip, SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)))
SCIP_EXPORT int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17859
static SCIP_DECL_CONSRESPROP(consRespropCumulative)
SCIP_EXPORT int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17350
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8338
static SCIP_RETCODE varMayRoundDown(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
#define CONSHDLR_ENFOPRIORITY
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip_solve.c:3433
SCIP_EXPORT int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11713
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
static SCIP_Bool impliesVubPrecedenceCondition(SCIP *scip, SCIP_VAR *var, SCIP_Real vubcoef, SCIP_Real vubconst, int duration)
int SCIPgetNRuns(SCIP *scip)
#define DEFAULT_SEPAOLD