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-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_cumulative.c
17  * @brief constraint handler for cumulative constraints
18  * @author Timo Berthold
19  * @author Stefan Heinz
20  * @author Jens Schulz
21  *
22  * Given:
23  * - a set of jobs, represented by their integer start time variables \f$S_j\f$, their array of processing times \f$p_j\f$ and of
24  * their demands \f$d_j\f$.
25  * - an integer resource capacity \f$C\f$
26  *
27  * The cumulative constraint ensures that for each point in time \f$t\f$ \f$\sum_{j: S_j \leq t < S_j + p_j} d_j \leq C\f$ holds.
28  *
29  * Separation:
30  * - can be done using binary start time model, see Pritskers, Watters and Wolfe
31  * - or by just separating relatively weak cuts on the integer start time variables
32  *
33  * Propagation:
34  * - time tabling, Klein & Scholl (1999)
35  * - Edge-finding from Petr Vilim, adjusted and simplified for dynamic repropagation
36  * (2009)
37  * - energetic reasoning, see Baptiste, Le Pape, Nuijten (2001)
38  *
39  */
40 
41 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
42 
43 #include <assert.h>
44 #include <string.h>
45 
46 #include "tclique/tclique.h"
47 #include "scip/cons_cumulative.h"
48 #include "scip/cons_linking.h"
49 #include "scip/cons_knapsack.h"
50 #include "scip/scipdefplugins.h"
51 
52 /**@name Constraint handler properties
53  *
54  * @{
55  */
56 
57 /* constraint handler properties */
58 #define CONSHDLR_NAME "cumulative"
59 #define CONSHDLR_DESC "cumulative constraint handler"
60 #define CONSHDLR_SEPAPRIORITY 2100000 /**< priority of the constraint handler for separation */
61 #define CONSHDLR_ENFOPRIORITY -2040000 /**< priority of the constraint handler for constraint enforcing */
62 #define CONSHDLR_CHECKPRIORITY -3030000 /**< priority of the constraint handler for checking feasibility */
63 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
64 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
65 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
66  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
67 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
68 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
69 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
70 #define CONSHDLR_DELAYPRESOL FALSE /**< should presolving method be delayed, if other presolvers found reductions? */
71 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
72 
73 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
74 
75 /**@} */
76 
77 /**@name Default parameter values
78  *
79  * @{
80  */
81 
82 /* default parameter values */
83 
84 /* separation */
85 #define DEFAULT_USEBINVARS FALSE /**< should the binary representation be used? */
86 #define DEFAULT_LOCALCUTS FALSE /**< should cuts be added only locally? */
87 #define DEFAULT_USECOVERCUTS TRUE /**< should covering cuts be added? */
88 #define DEFAULT_CUTSASCONSS TRUE /**< should the cuts be created as knapsack constraints? */
89 #define DEFAULT_SEPAOLD TRUE /**< shall old sepa algo be applied? */
90 
91 /* propagation */
92 #define DEFAULT_TTINFER TRUE /**< should time-table (core-times) propagator be used to infer bounds? */
93 #define DEFAULT_EFCHECK FALSE /**< should edge-finding be used to detect an overload? */
94 #define DEFAULT_EFINFER FALSE /**< should edge-finding be used to infer bounds? */
95 #define DEFAULT_USEADJUSTEDJOBS FALSE /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
96 #define DEFAULT_TTEFCHECK TRUE /**< should time-table edge-finding be used to detect an overload? */
97 #define DEFAULT_TTEFINFER TRUE /**< should time-table edge-finding be used to infer bounds? */
98 
99 /* presolving */
100 #define DEFAULT_DUALPRESOLVE TRUE /**< should dual presolving be applied? */
101 #define DEFAULT_COEFTIGHTENING FALSE /**< should coeffisient tightening be applied? */
102 #define DEFAULT_NORMALIZE TRUE /**< should demands and capacity be normalized? */
103 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
104 #define DEFAULT_DISJUNCTIVE TRUE /**< extract disjunctive constraints? */
105 #define DEFAULT_DETECTDISJUNCTIVE TRUE /**< search for conflict set via maximal cliques to detect disjunctive constraints */
106 #define DEFAULT_DETECTVARBOUNDS TRUE /**< search for conflict set via maximal cliques to detect variable bound constraints */
107 #define DEFAULT_MAXNODES 10000LL /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
109 /* enforcement */
110 #define DEFAULT_FILLBRANCHCANDS FALSE /**< should branching candidates be added to storage? */
112 /* conflict analysis */
113 #define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used during conflict analysis? */
115 /**@} */
116 
117 /**@name Event handler properties
118  *
119  * @{
120  */
121 
122 #define EVENTHDLR_NAME "cumulative"
123 #define EVENTHDLR_DESC "bound change event handler for cumulative constraints"
125 /**@} */
126 
127 /*
128  * Data structures
129  */
130 
131 /** constraint data for cumulative constraints */
132 struct SCIP_ConsData
133 {
134  SCIP_VAR** vars; /**< array of variable representing the start time of each job */
135  SCIP_Bool* downlocks; /**< array to store if the variable has a down lock */
136  SCIP_Bool* uplocks; /**< array to store if the variable has an uplock */
137  SCIP_CONS** linkingconss; /**< array of linking constraints for the integer variables */
138  SCIP_ROW** demandrows; /**< array of rows of linear relaxation of this problem */
139  SCIP_ROW** scoverrows; /**< array of rows of small cover cuts of this problem */
140  SCIP_ROW** bcoverrows; /**< array of rows of big cover cuts of this problem */
141  int* demands; /**< array containing corresponding demands */
142  int* durations; /**< array containing corresponding durations */
143  SCIP_Real resstrength1; /**< stores the resource strength 1*/
144  SCIP_Real resstrength2; /**< stores the resource strength 2 */
145  SCIP_Real cumfactor1; /**< stroes the cumulativeness of the constraint */
146  SCIP_Real disjfactor1; /**< stores the disjunctiveness of the constraint */
147  SCIP_Real disjfactor2; /**< stores the disjunctiveness of the constraint */
148  SCIP_Real estimatedstrength;
149  int nvars; /**< number of variables */
150  int varssize; /**< size of the arrays */
151  int ndemandrows; /**< number of rows of cumulative constrint for linear relaxation */
152  int demandrowssize; /**< size of array rows of demand rows */
153  int nscoverrows; /**< number of rows of small cover cuts */
154  int scoverrowssize; /**< size of array of small cover cuts */
155  int nbcoverrows; /**< number of rows of big cover cuts */
156  int bcoverrowssize; /**< size of array of big cover cuts */
157  int capacity; /**< available cumulative capacity */
158 
159  int hmin; /**< left bound of time axis to be considered (including hmin) */
160  int hmax; /**< right bound of time axis to be considered (not including hmax) */
161 
162  unsigned int signature; /**< constraint signature which is need for pairwise comparison */
163 
164  unsigned int validsignature:1; /**< is the signature valid */
165  unsigned int normalized:1; /**< is the constraint normalized */
166  unsigned int covercuts:1; /**< cover cuts are created? */
167  unsigned int propagated:1; /**< is constraint propagted */
168  unsigned int varbounds:1; /**< bool to store if variable bound strengthening was already preformed */
169  unsigned int triedsolving:1; /**< bool to store if we tried already to solve that constraint as independent subproblem */
170 
171 #ifdef SCIP_STATISTIC
172  int maxpeak;
173 #endif
174 };
175 
176 /** constraint handler data */
177 struct SCIP_ConshdlrData
178 {
179  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
180 
181  SCIP_Bool usebinvars; /**< should the binary variables be used? */
182  SCIP_Bool cutsasconss; /**< should the cumulative constraint create cuts as knapsack constraints? */
183  SCIP_Bool ttinfer; /**< should time-table (core-times) propagator be used to infer bounds? */
184  SCIP_Bool efcheck; /**< should edge-finding be used to detect an overload? */
185  SCIP_Bool efinfer; /**< should edge-finding be used to infer bounds? */
186  SCIP_Bool useadjustedjobs; /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
187  SCIP_Bool ttefcheck; /**< should time-table edge-finding be used to detect an overload? */
188  SCIP_Bool ttefinfer; /**< should time-table edge-finding be used to infer bounds? */
189  SCIP_Bool localcuts; /**< should cuts be added only locally? */
190  SCIP_Bool usecovercuts; /**< should covering cuts be added? */
191  SCIP_Bool sepaold; /**< shall old sepa algo be applied? */
192 
193 
194  SCIP_Bool fillbranchcands; /**< should branching candidates be added to storage? */
195 
196  SCIP_Bool dualpresolve; /**< should dual presolving be applied? */
197  SCIP_Bool coeftightening; /**< should coeffisient tightening be applied? */
198  SCIP_Bool normalize; /**< should demands and capacity be normalized? */
199  SCIP_Bool disjunctive; /**< extract disjunctive constraints? */
200  SCIP_Bool detectdisjunctive; /**< search for conflict set via maximal cliques to detect disjunctive constraints */
201  SCIP_Bool detectvarbounds; /**< search for conflict set via maximal cliques to detect variable bound constraints */
202  SCIP_Bool usebdwidening; /**< should bound widening be used during conflict analysis? */
203  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
204 
205  SCIP_Longint maxnodes; /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
206 
207  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)); /**< method to use a single cumulative condition */
208 
209  /* statistic values which are collected if SCIP_STATISTIC is defined */
210 #ifdef SCIP_STATISTIC
211  SCIP_Longint nlbtimetable; /**< number of times the lower bound was tightened by the time-table propagator */
212  SCIP_Longint nubtimetable; /**< number of times the upper bound was tightened by the time-table propagator */
213  SCIP_Longint ncutofftimetable; /**< number of times the a cutoff was detected due to time-table propagator */
214  SCIP_Longint nlbedgefinder; /**< number of times the lower bound was tightened by the edge-finder propagator */
215  SCIP_Longint nubedgefinder; /**< number of times the upper bound was tightened by the edge-finder propagator */
216  SCIP_Longint ncutoffedgefinder; /**< number of times the a cutoff was detected due to edge-finder propagator */
217  SCIP_Longint ncutoffoverload; /**< number of times the a cutoff was detected due to overload checking via edge-finding */
218  SCIP_Longint nlbTTEF; /**< number of times the lower bound was tightened by time-table edge-finding */
219  SCIP_Longint nubTTEF; /**< number of times the upper bound was tightened by time-table edge-finding */
220  SCIP_Longint ncutoffoverloadTTEF;/**< number of times the a cutoff was detected due to overload checking via time-table edge-finding */
221 
222  int nirrelevantjobs; /**< number of time a irrelevant/redundant jobs was removed form a constraint */
223  int nalwaysruns; /**< number of time a job removed form a constraint which run completely during the effective horizon */
224  int nremovedlocks; /**< number of times a up or down lock was removed */
225  int ndualfixs; /**< number of times a dual fix was performed by a single constraint */
226  int ndecomps; /**< number of times a constraint was decomposed */
227  int ndualbranchs; /**< number of times a dual branch was discoverd and applicable via probing */
228  int nallconsdualfixs; /**< number of times a dual fix was performed due to knowledge of all cumulative constraints */
229  int naddedvarbounds; /**< number of added variable bounds constraints */
230  int naddeddisjunctives; /**< number of added disjunctive constraints */
231 
232  SCIP_Bool iscopy; /**< Boolean to store if constraint handler is part of a copy */
233 #endif
234 };
235 
236 /**@name Inference Information Methods
237  *
238  * An inference information can be passed with each domain reduction to SCIP. This information is passed back to the
239  * constraint handler if the corresponding bound change has to be explained. It can be used to store information which
240  * help to construct a reason/explanation for a bound change. The inference information is limited to size of integer.
241  *
242  * In case of the cumulative constraint handler we store the used propagation algorithms for that particular bound
243  * change and the earliest start and latest completion time of all jobs in the conflict set.
244  *
245  * @{
246  */
247 
248 /** Propagation rules */
249 enum Proprule
250 {
251  PROPRULE_1_CORETIMES = 1, /**< core-time propagator */
252  PROPRULE_2_EDGEFINDING = 2, /**< edge-finder */
253  PROPRULE_3_TTEF = 3 /**< time-table edeg-finding */
254 };
255 typedef enum Proprule PROPRULE;
257 /** inference information */
258 struct InferInfo
259 {
260  union
261  {
262  /** struct to use the inference information */
263  struct
264  {
265  unsigned int proprule:2; /**< propagation rule that was applied */
266  unsigned int data1:15; /**< data field one */
267  unsigned int data2:15; /**< data field two */
268  } asbits;
269  int asint; /**< inference information as a single int value */
270  } val;
271 };
272 typedef struct InferInfo INFERINFO;
274 /** converts an integer into an inference information */
275 static
277  int i /**< integer to convert */
278  )
279 {
280  INFERINFO inferinfo;
281 
282  inferinfo.val.asint = i;
283 
284  return inferinfo;
285 }
286 
287 /** converts an inference information into an int */
288 static
289 int inferInfoToInt(
290  INFERINFO inferinfo /**< inference information to convert */
291  )
292 {
293  return inferinfo.val.asint;
294 }
295 
296 /** returns the propagation rule stored in the inference information */
297 static
298 PROPRULE inferInfoGetProprule(
299  INFERINFO inferinfo /**< inference information to convert */
300  )
301 {
302  return (PROPRULE) inferinfo.val.asbits.proprule;
303 }
304 
305 /** returns data field one of the inference information */
306 static
308  INFERINFO inferinfo /**< inference information to convert */
309  )
310 {
311  return (int) inferinfo.val.asbits.data1;
312 }
313 
314 /** returns data field two of the inference information */
315 static
317  INFERINFO inferinfo /**< inference information to convert */
318  )
319 {
320  return (int) inferinfo.val.asbits.data2;
321 }
322 
323 
324 /** constructs an inference information out of a propagation rule, an earliest start and a latest completion time */
325 static
327  PROPRULE proprule, /**< propagation rule that deduced the value */
328  int data1, /**< data field one */
329  int data2 /**< data field two */
330  )
331 {
332  INFERINFO inferinfo;
333 
334  /* check that the data menber are in the range of the available bits */
335  assert((int)proprule <= (1<<2)-1); /*lint !e685*/
336  assert(data1 >= 0 && data1 < (1<<15));
337  assert(data2 >= 0 && data2 < (1<<15));
338 
339  inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
340  inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
341  inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
342 
343  return inferinfo;
344 }
345 
346 /**@} */
347 
348 /*
349  * Local methods
350  */
351 
352 /**@name Miscellaneous Methods
353  *
354  * @{
355  */
356 
357 #ifndef NDEBUG
358 
359 /** compute the core of a job which lies in certain interval [begin, end) */
360 static
362  int begin, /**< begin of the interval */
363  int end, /**< end of the interval */
364  int ect, /**< earliest completion time */
365  int lst /**< latest start time */
366  )
367 {
368  int core;
369 
370  core = MAX(0, MIN(end, ect) - MAX(lst, begin));
371 
372  return core;
373 }
374 #else
375 #define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
376 #endif
377 
378 /** returns the implied earliest start time */
379 static
381  SCIP* scip, /**< SCIP data structure */
382  SCIP_VAR* var, /**< variable for which the implied est should be returned */
383  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
384  int* est /**< pointer to store the implied earliest start time */
385  )
386 { /*lint --e{715}*/
387 #if 0
388  SCIP_VAR** vbdvars;
389  SCIP_VAR* vbdvar;
390  SCIP_Real* vbdcoefs;
391  SCIP_Real* vbdconsts;
392  void* image;
393  int nvbdvars;
394  int v;
395 #endif
396 
397  (*est) = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
398 
399 #if 0
400  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
401 
402  nvbdvars = SCIPvarGetNVlbs(var);
403  vbdvars = SCIPvarGetVlbVars(var);
404  vbdcoefs = SCIPvarGetVlbCoefs(var);
405  vbdconsts = SCIPvarGetVlbConstants(var);
406 
407  for( v = 0; v < nvbdvars; ++v )
408  {
409  vbdvar = vbdvars[v];
410  assert(vbdvar != NULL);
411 
412  image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
413 
414  if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
415  {
416  int duration;
417  int vbdconst;
418 
419  duration = (int)(size_t)image;
420  vbdconst = SCIPconvertRealToInt(scip, vbdconsts[v]);
421 
422  SCIPdebugMessage("check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
424  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
425 
426  if( duration >= vbdconst )
427  {
428  int impliedest;
429 
430  impliedest = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
431 
432  if( (*est) < impliedest )
433  {
434  (*est) = impliedest;
435 
436  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
437  }
438  }
439  }
440  }
441 #endif
442 
443  return SCIP_OKAY;
444 }
445 
446 /** returns the implied latest completion time */
447 static
449  SCIP* scip, /**< SCIP data structure */
450  SCIP_VAR* var, /**< variable for which the implied est should be returned */
451  int duration, /**< duration of the given job */
452  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
453  int* lct /**< pointer to store the implied latest completion time */
454  )
455 { /*lint --e{715}*/
456 #if 0
457  SCIP_VAR** vbdvars;
458  SCIP_VAR* vbdvar;
459  SCIP_Real* vbdcoefs;
460  SCIP_Real* vbdconsts;
461  int nvbdvars;
462  int v;
463 #endif
464 
465  (*lct) = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
466 
467 #if 0
468  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
469 
470  nvbdvars = SCIPvarGetNVubs(var);
471  vbdvars = SCIPvarGetVubVars(var);
472  vbdcoefs = SCIPvarGetVubCoefs(var);
473  vbdconsts = SCIPvarGetVubConstants(var);
474 
475  for( v = 0; v < nvbdvars; ++v )
476  {
477  vbdvar = vbdvars[v];
478  assert(vbdvar != NULL);
479 
480  if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
481  {
482  int vbdconst;
483 
484  vbdconst = SCIPconvertRealToInt(scip, -vbdconsts[v]);
485 
486  SCIPdebugMessage("check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
488  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
489 
490  if( duration >= -vbdconst )
491  {
492  int impliedlct;
493 
494  impliedlct = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
495 
496  if( (*lct) > impliedlct )
497  {
498  (*lct) = impliedlct;
499 
500  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
501  }
502  }
503  }
504  }
505 #endif
506 
507  return SCIP_OKAY;
508 }
509 
510 /** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
511 static
513  SCIP* scip, /**< SCIP data structure */
514  SCIP_CONSDATA* consdata, /**< constraint data */
515  SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
516  int** coefs, /**< pointer to store the coefficients */
517  int* nvars, /**< number if collect binary variables */
518  int* startindices, /**< permutation with rspect to the start times */
519  int curtime, /**< current point in time */
520  int nstarted, /**< number of jobs that start before the curtime or at curtime */
521  int nfinished /**< number of jobs that finished before curtime or at curtime */
522  )
523 {
524  int nrowvars;
525  int startindex;
526  int size;
527 
528  size = 10;
529  nrowvars = 0;
530  startindex = nstarted - 1;
531 
532  SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
533  SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
534 
535  /* search for the (nstarted - nfinished) jobs which are active at curtime */
536  while( nstarted - nfinished > nrowvars )
537  {
538  SCIP_VAR* var;
539  int endtime;
540  int duration;
541  int demand;
542  int varidx;
543 
544  /* collect job information */
545  varidx = startindices[startindex];
546  assert(varidx >= 0 && varidx < consdata->nvars);
547 
548  var = consdata->vars[varidx];
549  duration = consdata->durations[varidx];
550  demand = consdata->demands[varidx];
551  assert(var != NULL);
552 
553  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
554 
555  /* check the end time of this job is larger than the curtime; in this case the job is still running */
556  if( endtime > curtime )
557  {
558  SCIP_VAR** binvars;
559  int* vals;
560  int nbinvars;
561  int start;
562  int end;
563  int b;
564 
565  /* check if the linking constraints exists */
566  assert(SCIPexistsConsLinking(scip, var));
567  assert(SCIPgetConsLinking(scip, var) != NULL);
568  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
569 
570  /* collect linking constraint information */
571  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
572  vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
573 
574  start = curtime - duration + 1;
575  end = MIN(curtime, endtime - duration);
576 
577  for( b = 0; b < nbinvars; ++b )
578  {
579  if( vals[b] < start )
580  continue;
581 
582  if( vals[b] > end )
583  break;
584 
585  assert(binvars[b] != NULL);
586 
587  /* ensure array proper array size */
588  if( size == *nvars )
589  {
590  size *= 2;
591  SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
592  SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
593  }
594 
595  (*vars)[*nvars] = binvars[b];
596  (*coefs)[*nvars] = demand;
597  (*nvars)++;
598  }
599  nrowvars++;
600  }
601 
602  startindex--;
603  }
604 
605  return SCIP_OKAY;
606 }
607 
608 /** collect all integer variable which belong to jobs which can run at the point of interest */
609 static
611  SCIP* scip, /**< SCIP data structure */
612  SCIP_CONSDATA* consdata, /**< constraint data */
613  SCIP_VAR*** activevars, /**< jobs that are currently running */
614  int* startindices, /**< permutation with rspect to the start times */
615  int curtime, /**< current point in time */
616  int nstarted, /**< number of jobs that start before the curtime or at curtime */
617  int nfinished, /**< number of jobs that finished before curtime or at curtime */
618  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
619  int* lhs /**< lhs for the new row sum of lbs + minoffset */
620  )
621 {
622  SCIP_VAR* var;
623  int startindex;
624  int endtime;
625  int duration;
626  int starttime;
627 
628  int varidx;
629  int sumofstarts;
630  int mindelta;
631  int counter;
632 
633  assert(curtime >= consdata->hmin);
634  assert(curtime < consdata->hmax);
635 
636  counter = 0;
637  sumofstarts = 0;
638 
639  mindelta = INT_MAX;
640 
641  startindex = nstarted - 1;
642 
643  /* search for the (nstarted - nfinished) jobs which are active at curtime */
644  while( nstarted - nfinished > counter )
645  {
646  assert(startindex >= 0);
647 
648  /* collect job information */
649  varidx = startindices[startindex];
650  assert(varidx >= 0 && varidx < consdata->nvars);
651 
652  var = consdata->vars[varidx];
653  duration = consdata->durations[varidx];
654  assert(duration > 0);
655  assert(var != NULL);
656 
657  if( lower )
658  starttime = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
659  else
660  starttime = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
661 
662  endtime = MIN(starttime + duration, consdata->hmax);
663 
664  /* check the end time of this job is larger than the curtime; in this case the job is still running */
665  if( endtime > curtime )
666  {
667  (*activevars)[counter] = var;
668  sumofstarts += starttime;
669  mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
670  counter++;
671  }
672 
673  startindex--;
674  }
675 
676  assert(mindelta > 0);
677  *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
678 
679  return SCIP_OKAY;
680 }
681 
682 /** initialize the sorted event point arrays */
683 static
685  SCIP* scip, /**< SCIP data structure */
686  int nvars, /**< number of start time variables (activities) */
687  SCIP_VAR** vars, /**< array of start time variables */
688  int* durations, /**< array of durations per start time variable */
689  int* starttimes, /**< array to store sorted start events */
690  int* endtimes, /**< array to store sorted end events */
691  int* startindices, /**< permutation with rspect to the start times */
692  int* endindices, /**< permutation with rspect to the end times */
693  SCIP_Bool local /**< shall local bounds be used */
694  )
695 {
696  SCIP_VAR* var;
697  int j;
698 
699  assert(vars != NULL || nvars == 0);
700 
701  /* assign variables, start and endpoints to arrays */
702  for ( j = 0; j < nvars; ++j )
703  {
704  assert(vars != NULL);
705 
706  var = vars[j];
707  assert(var != NULL);
708 
709  if( local )
710  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
711  else
712  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
713 
714  startindices[j] = j;
715 
716  if( local )
717  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
718  else
719  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
720 
721  endindices[j] = j;
722 
723  }
724 
725  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
726  SCIPsortIntInt(starttimes, startindices, j);
727  SCIPsortIntInt(endtimes, endindices, j);
728 }
729 
730 /** initialize the sorted event point arrays w.r.t. the given primal solutions */
731 static
733  SCIP* scip, /**< SCIP data structure */
734  SCIP_SOL* sol, /**< solution */
735  int nvars, /**< number of start time variables (activities) */
736  SCIP_VAR** vars, /**< array of start time variables */
737  int* durations, /**< array of durations per start time variable */
738  int* starttimes, /**< array to store sorted start events */
739  int* endtimes, /**< array to store sorted end events */
740  int* startindices, /**< permutation with rspect to the start times */
741  int* endindices /**< permutation with rspect to the end times */
742  )
743 {
744  SCIP_VAR* var;
745  int j;
746 
747  assert(vars != NULL || nvars == 0);
748 
749  /* assign variables, start and endpoints to arrays */
750  for ( j = 0; j < nvars; ++j )
751  {
752  assert(vars != NULL);
753 
754  var = vars[j];
755  assert(var != NULL);
756 
757  starttimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
758  startindices[j] = j;
759 
760  endtimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
761  endindices[j] = j;
762 
763  }
764 
765  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
766  SCIPsortIntInt(starttimes, startindices, j);
767  SCIPsortIntInt(endtimes, endindices, j);
768 }
769 
770 /** initialize the sorted event point arrays
771  *
772  * @todo Check the separation process!
773  */
774 static
776  SCIP* scip, /**< SCIP data structure */
777  SCIP_CONSDATA* consdata, /**< constraint data */
778  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
779  int* starttimes, /**< array to store sorted start events */
780  int* endtimes, /**< array to store sorted end events */
781  int* startindices, /**< permutation with rspect to the start times */
782  int* endindices, /**< permutation with rspect to the end times */
783  int* nvars, /**< number of variables that are integral */
784  SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
785  )
786 {
787  SCIP_VAR* var;
788  int tmpnvars;
789  int j;
790 
791  tmpnvars = consdata->nvars;
792  *nvars = 0;
793 
794  /* assign variables, start and endpoints to arrays */
795  for ( j = 0; j < tmpnvars; ++j )
796  {
797  var = consdata->vars[j];
798  assert(var != NULL);
799  assert(consdata->durations[j] > 0);
800  assert(consdata->demands[j] > 0);
801 
802  if( lower )
803  {
804  /* only consider jobs that are at their lower or upper bound */
805  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
806  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
807  continue;
808 
809 
810  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
811  startindices[*nvars] = j;
812 
813  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
814  endindices[*nvars] = j;
815 
816  SCIPdebugMessage("%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
817  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
818  consdata->durations[j],
819  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
820  consdata->demands[startindices[*nvars]]);
821 
822  (*nvars)++;
823  }
824  else
825  {
826  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
827  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
828  continue;
829 
830  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
831  startindices[*nvars] = j;
832 
833  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
834  endindices[*nvars] = j;
835 
836  SCIPdebugMessage("%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
837  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
838  consdata->durations[j],
839  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
840  consdata->demands[startindices[*nvars]]);
841 
842  (*nvars)++;
843  }
844  }
845 
846  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
847  SCIPsortIntInt(starttimes, startindices, *nvars);
848  SCIPsortIntInt(endtimes, endindices, *nvars);
849 
850 #ifdef SCIP_DEBUG
851  SCIPdebugMessage("sorted output %d\n", *nvars);
852 
853  for ( j = 0; j < *nvars; ++j )
854  {
855  SCIPdebugMessage("%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
856  startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
857  consdata->demands[startindices[j]]);
858  }
859 
860  for ( j = 0; j < *nvars; ++j )
861  {
862  SCIPdebugMessage("%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
863  consdata->demands[endindices[j]]);
864  }
865 #endif
866 }
867 
868 #ifdef SCIP_STATISTIC
869 /** this method checks for relevant intervals for energetic reasoning */
870 static
871 SCIP_RETCODE computeRelevantEnergyIntervals(
872  SCIP* scip, /**< SCIP data structure */
873  int nvars, /**< number of start time variables (activities) */
874  SCIP_VAR** vars, /**< array of start time variables */
875  int* durations, /**< array of durations */
876  int* demands, /**< array of demands */
877  int capacity, /**< cumulative capacity */
878  int hmin, /**< left bound of time axis to be considered (including hmin) */
879  int hmax, /**< right bound of time axis to be considered (not including hmax) */
880  int** timepoints, /**< array to store relevant points in time */
881  SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
882  int* ntimepoints, /**< pointer to store the number of timepoints */
883  int* maxdemand, /**< pointer to store maximum over all demands */
884  SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
885  )
886 {
887  int* starttimes; /* stores when each job is starting */
888  int* endtimes; /* stores when each job ends */
889  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
890  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
891 
892  SCIP_Real totaldemand;
893  int curtime; /* point in time which we are just checking */
894  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
895 
896  int j;
897 
898  assert( scip != NULL );
899  assert(durations != NULL);
900  assert(demands != NULL);
901  assert(capacity >= 0);
902 
903  /* if no activities are associated with this cumulative then this constraint is redundant */
904  if( nvars == 0 )
905  return SCIP_OKAY;
906 
907  assert(vars != NULL);
908 
909  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
910  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
911  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
912  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
913 
914  /* create event point arrays */
915  createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
916 
917  endindex = 0;
918  totaldemand = 0.0;
919 
920  *ntimepoints = 0;
921  (*timepoints)[0] = starttimes[0];
922  (*cumulativedemands)[0] = 0;
923  *maxdemand = 0;
924 
925  /* check each startpoint of a job whether the capacity is kept or not */
926  for( j = 0; j < nvars; ++j )
927  {
928  int lct;
929  int idx;
930 
931  curtime = starttimes[j];
932 
933  if( curtime >= hmax )
934  break;
935 
936  /* free all capacity usages of jobs the are no longer running */
937  while( endindex < nvars && endtimes[endindex] <= curtime )
938  {
939  int est;
940 
941  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
942  {
943  (*ntimepoints)++;
944  (*timepoints)[*ntimepoints] = endtimes[endindex];
945  (*cumulativedemands)[*ntimepoints] = 0;
946  }
947 
948  idx = endindices[endindex];
949  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
950  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
951  endindex++;
952 
953  (*cumulativedemands)[*ntimepoints] = totaldemand;
954  }
955 
956  idx = startindices[j];
957  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
958  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
959 
960  if( (*timepoints)[*ntimepoints] < curtime )
961  {
962  (*ntimepoints)++;
963  (*timepoints)[*ntimepoints] = curtime;
964  (*cumulativedemands)[*ntimepoints] = 0;
965  }
966 
967  (*cumulativedemands)[*ntimepoints] = totaldemand;
968 
969  /* add the relative capacity requirements for all job which start at the curtime */
970  while( j+1 < nvars && starttimes[j+1] == curtime )
971  {
972  ++j;
973  idx = startindices[j];
974  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
975  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
976 
977  (*cumulativedemands)[*ntimepoints] = totaldemand;
978  }
979  } /*lint --e{850}*/
980 
981  /* free all capacity usages of jobs that are no longer running */
982  while( endindex < nvars/* && endtimes[endindex] < hmax*/)
983  {
984  int est;
985  int idx;
986 
987  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
988  {
989  (*ntimepoints)++;
990  (*timepoints)[*ntimepoints] = endtimes[endindex];
991  (*cumulativedemands)[*ntimepoints] = 0;
992  }
993 
994  idx = endindices[endindex];
995  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
996  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
997  (*cumulativedemands)[*ntimepoints] = totaldemand;
998 
999  ++endindex;
1000  }
1001 
1002  (*ntimepoints)++;
1003  /* compute minimum free capacity */
1004  (*minfreecapacity) = INT_MAX;
1005  for( j = 0; j < *ntimepoints; ++j )
1006  {
1007  if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
1008  *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
1009  }
1010 
1011  /* free buffer arrays */
1012  SCIPfreeBufferArray(scip, &endindices);
1013  SCIPfreeBufferArray(scip, &startindices);
1014  SCIPfreeBufferArray(scip, &endtimes);
1015  SCIPfreeBufferArray(scip, &starttimes);
1016 
1017  return SCIP_OKAY;
1018 }
1019 
1020 /** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1021 static
1022 SCIP_RETCODE evaluateCumulativeness(
1023  SCIP* scip, /**< pointer to scip */
1024  SCIP_CONS* cons /**< cumulative constraint */
1025  )
1026 {
1027  SCIP_CONSDATA* consdata;
1028  int nvars;
1029  int v;
1030  int capacity;
1031 
1032  /* output values: */
1033  SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
1034  SCIP_Real cumfactor1;
1035  SCIP_Real resstrength1; /* overall strength */
1036  SCIP_Real resstrength2; /* timepoint wise maximum */
1037 
1038  /* helpful variables: */
1039  SCIP_Real globalpeak;
1040  SCIP_Real globalmaxdemand;
1041 
1042  /* get constraint data structure */
1043  consdata = SCIPconsGetData(cons);
1044  assert(consdata != NULL);
1045 
1046  nvars = consdata->nvars;
1047  capacity = consdata->capacity;
1048  globalpeak = 0.0;
1049  globalmaxdemand = 0.0;
1050 
1051  disjfactor2 = 0.0;
1052  cumfactor1 = 0.0;
1053  resstrength2 = 0.0;
1054 
1055  /* check each starting time (==each job, but inefficient) */
1056  for( v = 0; v < nvars; ++v )
1057  {
1058  SCIP_Real peak;
1059  SCIP_Real maxdemand;
1060  SCIP_Real deltademand;
1061  int ndemands;
1062  int nlarge;
1063 
1064  int timepoint;
1065  int j;
1066  timepoint = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
1067  peak = consdata->demands[v];
1068  ndemands = 1;
1069  maxdemand = 0;
1070  nlarge = 0;
1071 
1072  if( consdata->demands[v] > capacity / 3 )
1073  nlarge++;
1074 
1075  for( j = 0; j < nvars; ++j )
1076  {
1077  int lb;
1078 
1079  if( j == v )
1080  continue;
1081 
1082  maxdemand = 0.0;
1083  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
1084 
1085  if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
1086  {
1087  peak += consdata->demands[j];
1088  ndemands++;
1089 
1090  if( consdata->demands[j] > consdata->capacity / 3 )
1091  nlarge++;
1092  }
1093  }
1094 
1095  deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
1096  globalpeak = MAX(globalpeak, peak);
1097  globalmaxdemand = MAX(globalmaxdemand, maxdemand);
1098 
1099  if( peak > capacity )
1100  {
1101  disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
1102  cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
1103  resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
1104  }
1105  }
1106 
1107  resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
1108 
1109  consdata->maxpeak = SCIPconvertRealToInt(scip, globalpeak);
1110  consdata->disjfactor2 = disjfactor2;
1111  consdata->cumfactor1 = cumfactor1;
1112  consdata->resstrength2 = resstrength2;
1113  consdata->resstrength1 = resstrength1;
1114 
1115  /* get estimated res strength */
1116  {
1117  int* timepoints;
1118  SCIP_Real* estimateddemands;
1119  int ntimepoints;
1120  int maxdemand;
1121  SCIP_Real minfreecapacity;
1122 
1123  SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
1124  SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
1125 
1126  ntimepoints = 0;
1127  minfreecapacity = INT_MAX;
1128 
1129 
1130  SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
1131  consdata->durations, consdata->demands,
1132  capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1133  &ntimepoints, &maxdemand, &minfreecapacity) );
1134 
1135  /* free buffer arrays */
1136  SCIPfreeBufferArray(scip, &estimateddemands);
1137  SCIPfreeBufferArray(scip, &timepoints);
1138 
1139  consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
1140  }
1141 
1142  SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
1143  SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
1144  consdata->estimatedstrength);
1145 
1146  return SCIP_OKAY;
1147 }
1148 #endif
1149 
1150 /** gets the active variables together with the constant */
1151 static
1153  SCIP* scip, /**< SCIP data structure */
1154  SCIP_VAR** var, /**< pointer to store the active variable */
1155  int* scalar, /**< pointer to store the scalar */
1156  int* constant /**< pointer to store the constant */
1157  )
1158 {
1159  if( !SCIPvarIsActive(*var) )
1160  {
1161  SCIP_Real realscalar;
1162  SCIP_Real realconstant;
1163 
1164  realscalar = 1.0;
1165  realconstant = 0.0;
1166 
1168 
1169  /* transform variable to active variable */
1170  SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
1171  assert(!SCIPisZero(scip, realscalar));
1172  assert(SCIPvarIsActive(*var));
1173 
1174  if( realconstant < 0.0 )
1175  (*constant) = -SCIPconvertRealToInt(scip, -realconstant);
1176  else
1177  (*constant) = SCIPconvertRealToInt(scip, realconstant);
1178 
1179  if( realscalar < 0.0 )
1180  (*scalar) = -SCIPconvertRealToInt(scip, -realscalar);
1181  else
1182  (*scalar) = SCIPconvertRealToInt(scip, realscalar);
1183  }
1184  else
1185  {
1186  (*scalar) = 1;
1187  (*constant) = 0;
1188  }
1189 
1190  assert(*scalar != 0);
1191 
1192  return SCIP_OKAY;
1193 }
1194 
1195 /** computes the total energy of all jobs */
1196 static
1197 int computeTotalEnergy(
1198  int* durations, /**< array of job durations */
1199  int* demands, /**< array of job demands */
1200  int njobs /**< number of jobs */
1201  )
1202 {
1203  int energy;
1204  int j;
1205 
1206  energy = 0;
1207 
1208  for( j = 0; j < njobs; ++j )
1209  energy += durations[j] * demands[j];
1210 
1211  return energy;
1212 }
1213 
1214 /**@} */
1215 
1216 /**@name Default method to solve a cumulative condition
1217  *
1218  * @{
1219  */
1220 
1221 /** solve single cumulative condition using SCIP and a single cumulative constraint */
1222 static
1223 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1225  SCIP* subscip;
1226  SCIP_VAR** subvars;
1227  SCIP_CONS* cons;
1228  SCIP_RETCODE retcode;
1229  char name[SCIP_MAXSTRLEN];
1230  int v;
1231 
1232  assert(njobs > 0);
1233 
1234  (*solved) = FALSE;
1235  (*infeasible) = FALSE;
1236  (*unbounded) = FALSE;
1237  (*error) = FALSE;
1238 
1239  SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1240 
1241  /* initialize the sub-problem */
1242  SCIP_CALL( SCIPcreate(&subscip) );
1243 
1244  /* copy all plugins */
1246 
1247  /* create the subproblem */
1248  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1249 
1250  SCIP_CALL( SCIPallocMemoryArray(subscip, &subvars, njobs) );
1251 
1252  /* create for each job a start time variable */
1253  for( v = 0; v < njobs; ++v )
1254  {
1255  SCIP_Real objval;
1256 
1257  /* construct varibale name */
1258  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
1259 
1260  if( objvals == NULL )
1261  objval = 0.0;
1262  else
1263  objval = objvals[v];
1264 
1265  SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
1266  SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
1267  }
1268 
1269  /* create cumulative constraint */
1270  SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
1271  njobs, subvars, durations, demands, capacity) );
1272 
1273  /* set effective horizon */
1274  SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
1275  SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
1276 
1277  /* add cumulative constraint */
1278  SCIP_CALL( SCIPaddCons(subscip, cons) );
1279  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1280 
1281  /* set CP solver settings
1282  *
1283  * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
1284  * time limit.
1285  */
1287 
1288  /* do not abort subproblem on CTRL-C */
1289  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1290 
1291  /* disable output to console */
1292  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1293 
1294  /* set limits for the subproblem */
1295  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1296  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1297  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1298 
1299  /* solve single cumulative constraint by branch and bound */
1300  retcode = SCIPsolve(subscip);
1301 
1302  if( retcode != SCIP_OKAY )
1303  (*error) = TRUE;
1304  else
1305  {
1306  SCIPdebugMessage("solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1307 
1308  /* evaluated solution status */
1309  switch( SCIPgetStatus(subscip) )
1310  {
1311  case SCIP_STATUS_INFORUNBD:
1313  (*infeasible) = TRUE;
1314  (*solved) = TRUE;
1315  break;
1316  case SCIP_STATUS_UNBOUNDED:
1317  (*unbounded) = TRUE;
1318  (*solved) = TRUE;
1319  break;
1320  case SCIP_STATUS_OPTIMAL:
1321  {
1322  SCIP_SOL* sol;
1323  SCIP_Real solval;
1324 
1325  sol = SCIPgetBestSol(subscip);
1326  assert(sol != NULL);
1327 
1328  for( v = 0; v < njobs; ++v )
1329  {
1330  solval = SCIPgetSolVal(subscip, sol, subvars[v]);
1331 
1332  ests[v] = solval;
1333  lsts[v] = solval;
1334  }
1335  (*solved) = TRUE;
1336  break;
1337  }
1338  case SCIP_STATUS_NODELIMIT:
1340  case SCIP_STATUS_TIMELIMIT:
1341  case SCIP_STATUS_MEMLIMIT:
1343  /* transfer the global bound changes */
1344  for( v = 0; v < njobs; ++v )
1345  {
1346  ests[v] = SCIPvarGetLbGlobal(subvars[v]);
1347  lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
1348  }
1349  (*solved) = FALSE;
1350  break;
1351 
1352  case SCIP_STATUS_UNKNOWN:
1354  case SCIP_STATUS_GAPLIMIT:
1355  case SCIP_STATUS_SOLLIMIT:
1357  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1358  return SCIP_INVALIDDATA;
1359  }
1360  }
1361 
1362  /* release all variables */
1363  for( v = 0; v < njobs; ++v )
1364  {
1365  SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1366  }
1367 
1368  SCIPfreeMemoryArray(subscip, &subvars);
1369 
1370  SCIP_CALL( SCIPfree(&subscip) );
1371 
1372  return SCIP_OKAY;
1373 }
1374 
1375 #if 0
1376 /** solve single cumulative condition using SCIP and the time indexed formulation */
1377 static
1378 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1379 {
1380  SCIP* subscip;
1381  SCIP_VAR*** binvars;
1382  SCIP_RETCODE retcode;
1383  char name[SCIP_MAXSTRLEN];
1384  int minest;
1385  int maxlct;
1386  int t;
1387  int v;
1388 
1389  assert(njobs > 0);
1390 
1391  (*solved) = FALSE;
1392  (*infeasible) = FALSE;
1393  (*unbounded) = FALSE;
1394  (*error) = FALSE;
1395 
1396  SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1397 
1398  /* initialize the sub-problem */
1399  SCIP_CALL( SCIPcreate(&subscip) );
1400 
1401  /* copy all plugins */
1403 
1404  /* create the subproblem */
1405  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1406 
1407  SCIP_CALL( SCIPallocMemoryArray(subscip, &binvars, njobs) );
1408 
1409  minest = INT_MAX;
1410  maxlct = INT_MIN;
1411 
1412  /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1413  * partitioning constrain which forces that job starts
1414  */
1415  for( v = 0; v < njobs; ++v )
1416  {
1417  SCIP_CONS* cons;
1418  SCIP_Real objval;
1419  int timeinterval;
1420  int est;
1421  int lst;
1422 
1423  if( objvals == NULL )
1424  objval = 0.0;
1425  else
1426  objval = objvals[v];
1427 
1428  est = ests[v];
1429  lst = lsts[v];
1430 
1431  /* compute number of possible start points */
1432  timeinterval = lst - est + 1;
1433  assert(timeinterval > 0);
1434 
1435  /* compute the smallest earliest start time and largest latest completion time */
1436  minest = MIN(minest, est);
1437  maxlct = MAX(maxlct, lst + durations[v]);
1438 
1439  /* construct constraint name */
1440  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1441 
1442  SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1443 
1444  SCIP_CALL( SCIPallocMemoryArray(subscip, &binvars[v], timeinterval) );
1445 
1446  for( t = 0; t < timeinterval; ++t )
1447  {
1448  SCIP_VAR* binvar;
1449 
1450  /* construct varibale name */
1451  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1452 
1453  SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1454  SCIP_CALL( SCIPaddVar(subscip, binvar) );
1455 
1456  /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1457  SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1458 
1459  binvars[v][t] = binvar;
1460  }
1461 
1462  /* add and release the set partitioning constraint */
1463  SCIP_CALL( SCIPaddCons(subscip, cons) );
1464  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1465  }
1466 
1467  /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1468  hmin = MAX(hmin, minest);
1469  hmax = MIN(hmax, maxlct);
1470  assert(hmin > INT_MIN);
1471  assert(hmax < INT_MAX);
1472  assert(hmin < hmax);
1473 
1474  /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1475  for( t = hmin; t < hmax; ++t )
1476  {
1477  SCIP_CONS* cons;
1478 
1479  /* construct constraint name */
1480  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1481 
1482  /* create an empty knapsack constraint */
1483  SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1484 
1485  /* add all jobs which potentially can be processed at that time point */
1486  for( v = 0; v < njobs; ++v )
1487  {
1488  int duration;
1489  int demand;
1490  int start;
1491  int end;
1492  int est;
1493  int lst;
1494  int k;
1495 
1496  est = ests[v];
1497  lst = lsts[v] ;
1498 
1499  duration = durations[v];
1500  assert(duration > 0);
1501 
1502  /* check if the varibale is processed potentially at time point t */
1503  if( t < est || t >= lst + duration )
1504  continue;
1505 
1506  demand = demands[v];
1507  assert(demand >= 0);
1508 
1509  start = MAX(t - duration + 1, est);
1510  end = MIN(t, lst);
1511 
1512  assert(start <= end);
1513 
1514  for( k = start; k <= end; ++k )
1515  {
1516  assert(binvars[v][k] != NULL);
1517  SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1518  }
1519  }
1520 
1521  /* add and release the knapsack constraint */
1522  SCIP_CALL( SCIPaddCons(subscip, cons) );
1523  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1524  }
1525 
1526  /* do not abort subproblem on CTRL-C */
1527  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1528 
1529  /* disable output to console */
1530  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1531 
1532  /* set limits for the subproblem */
1533  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1534  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1535  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1536 
1537  /* solve single cumulative constraint by branch and bound */
1538  retcode = SCIPsolve(subscip);
1539 
1540  if( retcode != SCIP_OKAY )
1541  (*error) = TRUE;
1542  else
1543  {
1544  SCIPdebugMessage("solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1545 
1546  /* evaluated solution status */
1547  switch( SCIPgetStatus(subscip) )
1548  {
1549  case SCIP_STATUS_INFORUNBD:
1551  (*infeasible) = TRUE;
1552  (*solved) = TRUE;
1553  break;
1554  case SCIP_STATUS_UNBOUNDED:
1555  (*unbounded) = TRUE;
1556  (*solved) = TRUE;
1557  break;
1558  case SCIP_STATUS_OPTIMAL:
1559  {
1560  SCIP_SOL* sol;
1561 
1562  sol = SCIPgetBestSol(subscip);
1563  assert(sol != NULL);
1564 
1565  for( v = 0; v < njobs; ++v )
1566  {
1567  int timeinterval;
1568  int est;
1569  int lst;
1570 
1571  est = ests[v];
1572  lst = lsts[v];
1573 
1574  /* compute number of possible start points */
1575  timeinterval = lst - est + 1;
1576 
1577  /* check which binary varibale is set to one */
1578  for( t = 0; t < timeinterval; ++t )
1579  {
1580  if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1581  {
1582  ests[v] = est + t;
1583  lsts[v] = est + t;
1584  break;
1585  }
1586  }
1587  }
1588 
1589  (*solved) = TRUE;
1590  break;
1591  }
1592  case SCIP_STATUS_NODELIMIT:
1594  case SCIP_STATUS_TIMELIMIT:
1595  case SCIP_STATUS_MEMLIMIT:
1597  /* transfer the global bound changes */
1598  for( v = 0; v < njobs; ++v )
1599  {
1600  int timeinterval;
1601  int est;
1602  int lst;
1603 
1604  est = ests[v];
1605  lst = lsts[v];
1606 
1607  /* compute number of possible start points */
1608  timeinterval = lst - est + 1;
1609 
1610  /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1611  for( t = 0; t < timeinterval; ++t )
1612  {
1613  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1614  {
1615  ests[v] = est + t;
1616  break;
1617  }
1618  }
1619 
1620  /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1621  for( t = timeinterval - 1; t >= 0; --t )
1622  {
1623  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1624  {
1625  lsts[v] = est + t;
1626  break;
1627  }
1628  }
1629  }
1630  (*solved) = FALSE;
1631  break;
1632 
1633  case SCIP_STATUS_UNKNOWN:
1635  case SCIP_STATUS_GAPLIMIT:
1636  case SCIP_STATUS_SOLLIMIT:
1638  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1639  return SCIP_INVALIDDATA;
1640  }
1641  }
1642 
1643  /* release all variables */
1644  for( v = 0; v < njobs; ++v )
1645  {
1646  int timeinterval;
1647  int est;
1648  int lst;
1649 
1650  est = ests[v];
1651  lst = lsts[v];
1652 
1653  /* compute number of possible start points */
1654  timeinterval = lst - est + 1;
1655 
1656  for( t = 0; t < timeinterval; ++t )
1657  {
1658  SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1659  }
1660  SCIPfreeMemoryArray(subscip, &binvars[v]);
1661  }
1662 
1663  SCIPfreeMemoryArray(subscip, &binvars);
1664 
1665  SCIP_CALL( SCIPfree(&subscip) );
1666 
1667  return SCIP_OKAY;
1668 }
1669 #endif
1670 
1671 /**@} */
1672 
1673 /**@name Constraint handler data
1674  *
1675  * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1676  * handler.
1677  *
1678  * @{
1679  */
1680 
1681 /** creates constaint handler data for cumulative constraint handler */
1682 static
1684  SCIP* scip, /**< SCIP data structure */
1685  SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1686  SCIP_EVENTHDLR* eventhdlr /**< event handler */
1687  )
1688 {
1689  /* create precedence constraint handler data */
1690  assert(scip != NULL);
1691  assert(conshdlrdata != NULL);
1692  assert(eventhdlr != NULL);
1693 
1694  SCIP_CALL( SCIPallocMemory(scip, conshdlrdata) );
1695 
1696  /* set event handler for checking if bounds of start time variables are tighten */
1697  (*conshdlrdata)->eventhdlr = eventhdlr;
1698 
1699  /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1700  (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1701 
1702 #ifdef SCIP_STATISTIC
1703  (*conshdlrdata)->nlbtimetable = 0;
1704  (*conshdlrdata)->nubtimetable = 0;
1705  (*conshdlrdata)->ncutofftimetable = 0;
1706  (*conshdlrdata)->nlbedgefinder = 0;
1707  (*conshdlrdata)->nubedgefinder = 0;
1708  (*conshdlrdata)->ncutoffedgefinder = 0;
1709  (*conshdlrdata)->ncutoffoverload = 0;
1710  (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1711 
1712  (*conshdlrdata)->nirrelevantjobs = 0;
1713  (*conshdlrdata)->nalwaysruns = 0;
1714  (*conshdlrdata)->nremovedlocks = 0;
1715  (*conshdlrdata)->ndualfixs = 0;
1716  (*conshdlrdata)->ndecomps = 0;
1717  (*conshdlrdata)->ndualbranchs = 0;
1718  (*conshdlrdata)->nallconsdualfixs = 0;
1719  (*conshdlrdata)->naddedvarbounds = 0;
1720  (*conshdlrdata)->naddeddisjunctives = 0;
1721 #endif
1722 
1723  return SCIP_OKAY;
1724 }
1725 
1726 /** frees constraint handler data for logic or constraint handler */
1727 static
1728 void conshdlrdataFree(
1729  SCIP* scip, /**< SCIP data structure */
1730  SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1731  )
1732 {
1733  assert(conshdlrdata != NULL);
1734  assert(*conshdlrdata != NULL);
1735 
1736  SCIPfreeMemory(scip, conshdlrdata);
1737 }
1738 
1739 /**@} */
1740 
1741 
1742 /**@name Constraint data methods
1743  *
1744  * @{
1745  */
1746 
1747 /** catches bound change events for all variables in transformed cumulative constraint */
1748 static
1750  SCIP* scip, /**< SCIP data structure */
1751  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1752  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1753  )
1754 {
1755  int v;
1756 
1757  assert(scip != NULL);
1758  assert(consdata != NULL);
1759  assert(eventhdlr != NULL);
1760 
1761  /* catch event for every single variable */
1762  for( v = 0; v < consdata->nvars; ++v )
1763  {
1764  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1765  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1766  }
1767 
1768  return SCIP_OKAY;
1769 }
1770 
1771 /** drops events for variable at given position */
1772 static
1774  SCIP* scip, /**< SCIP data structure */
1775  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1776  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1777  int pos /**< array position of variable to catch bound change events for */
1778  )
1779 {
1780  assert(scip != NULL);
1781  assert(consdata != NULL);
1782  assert(eventhdlr != NULL);
1783  assert(0 <= pos && pos < consdata->nvars);
1784  assert(consdata->vars[pos] != NULL);
1785 
1786  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1787  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1788 
1789  return SCIP_OKAY;
1790 }
1791 
1792 /** drops bound change events for all variables in transformed linear constraint */
1793 static
1795  SCIP* scip, /**< SCIP data structure */
1796  SCIP_CONSDATA* consdata, /**< linear constraint data */
1797  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1798  )
1799 {
1800  int v;
1801 
1802  assert(scip != NULL);
1803  assert(consdata != NULL);
1804 
1805  /* drop event of every single variable */
1806  for( v = 0; v < consdata->nvars; ++v )
1807  {
1808  SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1809  }
1810 
1811  return SCIP_OKAY;
1812 }
1813 
1814 /** initialize variable lock data structure */
1815 static
1816 void initializeLocks(
1817  SCIP_CONSDATA* consdata, /**< constraint data */
1818  SCIP_Bool locked /**< should the variable be locked? */
1819  )
1820 {
1821  int nvars;
1822  int v;
1823 
1824  nvars = consdata->nvars;
1825 
1826  /* initialize locking arrays */
1827  for( v = 0; v < nvars; ++v )
1828  {
1829  consdata->downlocks[v] = locked;
1830  consdata->uplocks[v] = locked;
1831  }
1832 }
1833 
1834 /** creates constraint data of cumulative constraint */
1835 static
1837  SCIP* scip, /**< SCIP data structure */
1838  SCIP_CONSDATA** consdata, /**< pointer to consdata */
1839  SCIP_VAR** vars, /**< array of integer variables */
1840  SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1841  int* durations, /**< array containing corresponding durations */
1842  int* demands, /**< array containing corresponding demands */
1843  int nvars, /**< number of variables */
1844  int capacity, /**< available cumulative capacity */
1845  int hmin, /**< left bound of time axis to be considered (including hmin) */
1846  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1847  SCIP_Bool check /**< is the corresponding constraint a check constraint */
1848  )
1849 {
1850  int v;
1851 
1852  assert(scip != NULL);
1853  assert(consdata != NULL);
1854  assert(vars != NULL || nvars > 0);
1855  assert(demands != NULL);
1856  assert(durations != NULL);
1857  assert(capacity >= 0);
1858  assert(hmin >= 0);
1859  assert(hmin < hmax);
1860 
1861  /* create constraint data */
1862  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1863 
1864  (*consdata)->hmin = hmin;
1865  (*consdata)->hmax = hmax;
1866 
1867  (*consdata)->capacity = capacity;
1868  (*consdata)->demandrows = NULL;
1869  (*consdata)->demandrowssize = 0;
1870  (*consdata)->ndemandrows = 0;
1871  (*consdata)->scoverrows = NULL;
1872  (*consdata)->nscoverrows = 0;
1873  (*consdata)->scoverrowssize = 0;
1874  (*consdata)->bcoverrows = NULL;
1875  (*consdata)->nbcoverrows = 0;
1876  (*consdata)->bcoverrowssize = 0;
1877  (*consdata)->nvars = nvars;
1878  (*consdata)->varssize = nvars;
1879  (*consdata)->signature = 0;
1880  (*consdata)->validsignature = FALSE;
1881  (*consdata)->normalized = FALSE;
1882  (*consdata)->covercuts = FALSE;
1883  (*consdata)->propagated = FALSE;
1884  (*consdata)->varbounds = FALSE;
1885  (*consdata)->triedsolving = FALSE;
1886 
1887  if( nvars > 0 )
1888  {
1889  assert(vars != NULL); /* for flexelint */
1890 
1891  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1892  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1893  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1894  (*consdata)->linkingconss = NULL;
1895 
1896  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1897  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1898 
1899  /* initialize variable lock data structure; the locks are only used if the contraint is a check constraint */
1900  initializeLocks(*consdata, check);
1901 
1902  if( linkingconss != NULL )
1903  {
1904  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
1905  }
1906 
1907  /* transform variables, if they are not yet transformed */
1908  if( SCIPisTransformed(scip) )
1909  {
1910  SCIPdebugMessage("get tranformed variables and constraints\n");
1911 
1912  /* get transformed variables and do NOT captures these */
1913  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1914 
1915  /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
1916  * been multi-aggregated
1917  */
1918  for( v = 0; v < nvars; ++v )
1919  {
1920  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
1921  }
1922 
1923  if( linkingconss != NULL )
1924  {
1925  /* get transformed constraints and captures these */
1926  SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
1927 
1928  for( v = 0; v < nvars; ++v )
1929  assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
1930  }
1931  }
1932  }
1933  else
1934  {
1935  (*consdata)->vars = NULL;
1936  (*consdata)->downlocks = NULL;
1937  (*consdata)->uplocks = NULL;
1938  (*consdata)->demands = NULL;
1939  (*consdata)->durations = NULL;
1940  (*consdata)->linkingconss = NULL;
1941  }
1942 
1943  /* initialize values for running propagation algorithms efficiently */
1944  (*consdata)->resstrength1 = -1.0;
1945  (*consdata)->resstrength2 = -1.0;
1946  (*consdata)->cumfactor1 = -1.0;
1947  (*consdata)->disjfactor1 = -1.0;
1948  (*consdata)->disjfactor2 = -1.0;
1949  (*consdata)->estimatedstrength = -1.0;
1950 
1951  SCIPstatistic( (*consdata)->maxpeak = -1 );
1952 
1953  return SCIP_OKAY;
1954 }
1955 
1956 /** releases LP rows of constraint data and frees rows array */
1957 static
1959  SCIP* scip, /**< SCIP data structure */
1960  SCIP_CONSDATA** consdata /**< constraint data */
1961  )
1962 {
1963  int r;
1964 
1965  assert(consdata != NULL);
1966  assert(*consdata != NULL);
1967 
1968  for( r = 0; r < (*consdata)->ndemandrows; ++r )
1969  {
1970  assert((*consdata)->demandrows[r] != NULL);
1971  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
1972  }
1973 
1974  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
1975 
1976  (*consdata)->ndemandrows = 0;
1977  (*consdata)->demandrowssize = 0;
1978 
1979  /* free rows of cover cuts */
1980  for( r = 0; r < (*consdata)->nscoverrows; ++r )
1981  {
1982  assert((*consdata)->scoverrows[r] != NULL);
1983  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
1984  }
1985 
1986  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
1987 
1988  (*consdata)->nscoverrows = 0;
1989  (*consdata)->scoverrowssize = 0;
1990 
1991  for( r = 0; r < (*consdata)->nbcoverrows; ++r )
1992  {
1993  assert((*consdata)->bcoverrows[r] != NULL);
1994  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
1995  }
1996 
1997  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
1998 
1999  (*consdata)->nbcoverrows = 0;
2000  (*consdata)->bcoverrowssize = 0;
2001 
2002  (*consdata)->covercuts = FALSE;
2003 
2004  return SCIP_OKAY;
2005 }
2006 
2007 /** frees a cumulative constraint data */
2008 static
2010  SCIP* scip, /**< SCIP data structure */
2011  SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2012  )
2013 {
2014  int varssize;
2015  int nvars;
2016 
2017  assert(consdata != NULL);
2018  assert(*consdata != NULL);
2019 
2020  nvars = (*consdata)->nvars;
2021  varssize = (*consdata)->varssize;
2022 
2023  if( varssize > 0 )
2024  {
2025  int v;
2026 
2027  /* release and free the rows */
2028  SCIP_CALL( consdataFreeRows(scip, consdata) );
2029 
2030  /* release the linking constraints if they were generated */
2031  if( (*consdata)->linkingconss != NULL )
2032  {
2033  for( v = nvars-1; v >= 0; --v )
2034  {
2035  assert((*consdata)->linkingconss[v] != NULL );
2036  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2037  }
2038 
2039  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2040  }
2041 
2042  /* free arrays */
2043  SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2044  SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2045  SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2046  SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2047  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2048  }
2049 
2050  /* free memory */
2051  SCIPfreeBlockMemory(scip, consdata);
2052 
2053  return SCIP_OKAY;
2054 }
2055 
2056 /** prints cumulative constraint to file stream */
2057 static
2058 void consdataPrint(
2059  SCIP* scip, /**< SCIP data structure */
2060  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2061  FILE* file /**< output file (or NULL for standard output) */
2062  )
2063 {
2064  int v;
2065 
2066  assert(consdata != NULL);
2067 
2068  /* print coefficients */
2069  SCIPinfoMessage( scip, file, "cumulative(");
2070 
2071  for( v = 0; v < consdata->nvars; ++v )
2072  {
2073  assert(consdata->vars[v] != NULL);
2074  if( v > 0 )
2075  SCIPinfoMessage(scip, file, ", ");
2076  SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2077  SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2078  consdata->durations[v], consdata->demands[v]);
2079  }
2080  SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2081 }
2082 
2083 /** deletes coefficient at given position from constraint data */
2084 static
2086  SCIP* scip, /**< SCIP data structure */
2087  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2088  SCIP_CONS* cons, /**< knapsack constraint */
2089  int pos /**< position of coefficient to delete */
2090  )
2091 {
2092  SCIP_CONSHDLR* conshdlr;
2093  SCIP_CONSHDLRDATA* conshdlrdata;
2094 
2095  assert(scip != NULL);
2096  assert(consdata != NULL);
2097  assert(cons != NULL);
2098  assert(SCIPconsIsTransformed(cons));
2099  assert(!SCIPinProbing(scip));
2100 
2101  SCIPdebugMessage("cumulative constraint <%s>: remove variable <%s>\n",
2102  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2103 
2104  /* remove the rounding locks for the deleted variable */
2105  SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2106 
2107  consdata->downlocks[pos] = FALSE;
2108  consdata->uplocks[pos] = FALSE;
2109 
2110  if( consdata->linkingconss != NULL )
2111  {
2112  SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2113  }
2114 
2115  /* get event handler */
2116  conshdlr = SCIPconsGetHdlr(cons);
2117  assert(conshdlr != NULL);
2118  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2119  assert(conshdlrdata != NULL);
2120  assert(conshdlrdata->eventhdlr != NULL);
2121 
2122  /* drop events */
2123  SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2124 
2125  SCIPdebugMessage("remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2126  SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2127 
2128 
2129  /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2130  * position
2131  */
2132  if( pos != consdata->nvars - 1 )
2133  {
2134  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2135  consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2136  consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2137  consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2138  consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2139 
2140  if( consdata->linkingconss != NULL )
2141  {
2142  consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2143  }
2144  }
2145 
2146  consdata->nvars--;
2147  consdata->validsignature = FALSE;
2148  consdata->normalized = FALSE;
2149 
2150  return SCIP_OKAY;
2151 }
2152 
2153 /** collect linking constraints for each integer variable */
2154 static
2156  SCIP* scip, /**< SCIP data structure */
2157  SCIP_CONSDATA* consdata /**< pointer to consdata */
2158  )
2159 {
2160  int nvars;
2161  int v;
2162 
2163  assert(scip != NULL);
2164  assert(consdata != NULL);
2165 
2166  nvars = consdata->nvars;
2167  assert(nvars > 0);
2168  assert(consdata->linkingconss == NULL);
2169 
2170  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2171 
2172  for( v = 0; v < nvars; ++v )
2173  {
2174  SCIP_CONS* cons;
2175  SCIP_VAR* var;
2176 
2177  var = consdata->vars[v];
2178  assert(var != NULL);
2179 
2180  SCIPdebugMessage("linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2181 
2182  /* create linking constraint if it does not exist yet */
2183  if( !SCIPexistsConsLinking(scip, var) )
2184  {
2185  char name[SCIP_MAXSTRLEN];
2186 
2187  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2188 
2189  /* creates and captures an linking constraint */
2190  SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2191  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2192  SCIP_CALL( SCIPaddCons(scip, cons) );
2193  consdata->linkingconss[v] = cons;
2194  }
2195  else
2196  {
2197  consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2198  SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2199  }
2200 
2201  assert(SCIPexistsConsLinking(scip, var));
2202  assert(consdata->linkingconss[v] != NULL);
2203  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2204  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2205  }
2206 
2207  return SCIP_OKAY;
2208 }
2209 
2210 /**@} */
2211 
2212 
2213 /**@name Check methods
2214  *
2215  * @{
2216  */
2217 
2218 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2219  * given solution is satisfied
2220  */
2221 static
2223  SCIP* scip, /**< SCIP data structure */
2224  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2225  int nvars, /**< number of variables (jobs) */
2226  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2227  int* durations, /**< array containing corresponding durations */
2228  int* demands, /**< array containing corresponding demands */
2229  int capacity, /**< available cumulative capacity */
2230  int hmin, /**< left bound of time axis to be considered (including hmin) */
2231  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2232  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2233  SCIP_CONS* cons, /**< constraint which is checked */
2234  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2235  )
2236 {
2237  int* startsolvalues; /* stores when each job is starting */
2238  int* endsolvalues; /* stores when each job ends */
2239  int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2240  int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2241 
2242  int freecapacity;
2243  int curtime; /* point in time which we are just checking */
2244  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2245  int j;
2246 
2247  assert(scip != NULL);
2248  assert(violated != NULL);
2249 
2250  (*violated) = FALSE;
2251 
2252  if( nvars == 0 )
2253  return SCIP_OKAY;
2254 
2255  assert(vars != NULL);
2256  assert(demands != NULL);
2257  assert(durations != NULL);
2258 
2259  /* compute time points where we have to check whether capacity constraint is infeasible or not */
2260  SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2261  SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2262  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2263  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2264 
2265  /* assign variables, start and endpoints to arrays */
2266  for ( j = 0; j < nvars; ++j )
2267  {
2268  int solvalue;
2269 
2270  /* the constraint of the cumulative constraint handler should be called after the integrality check */
2271  assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2272 
2273  solvalue = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2274 
2275  /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2276  * jobs which start before hmin to hmin
2277  */
2278  startsolvalues[j] = MAX(solvalue, hmin);
2279  startindices[j] = j;
2280 
2281  endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2282  endindices[j] = j;
2283  }
2284 
2285  /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2286  * corresponding indices in the same way)
2287  */
2288  SCIPsortIntInt(startsolvalues, startindices, nvars);
2289  SCIPsortIntInt(endsolvalues, endindices, nvars);
2290 
2291  endindex = 0;
2292  freecapacity = capacity;
2293 
2294  /* check each start point of a job whether the capacity is kept or not */
2295  for( j = 0; j < nvars; ++j )
2296  {
2297  /* only check intervals [hmin,hmax) */
2298  curtime = startsolvalues[j];
2299 
2300  if( curtime >= hmax )
2301  break;
2302 
2303  /* subtract all capacity needed up to this point */
2304  freecapacity -= demands[startindices[j]];
2305  while( j+1 < nvars && startsolvalues[j+1] == curtime )
2306  {
2307  j++;
2308  freecapacity -= demands[startindices[j]];
2309  }
2310 
2311  /* free all capacity usages of jobs that are no longer running */
2312  while( endindex < nvars && curtime >= endsolvalues[endindex] )
2313  {
2314  freecapacity += demands[endindices[endindex]];
2315  ++endindex;
2316  }
2317  assert(freecapacity <= capacity);
2318 
2319  /* check freecapacity to be smaller than zero */
2320  if( freecapacity < 0 && curtime >= hmin )
2321  {
2322  SCIPdebugMessage("freecapacity = %3d\n", freecapacity);
2323  (*violated) = TRUE;
2324 
2325  if( printreason )
2326  {
2327  int i;
2328 
2329  /* first state the violated constraints */
2330  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2331 
2332  /* second state the reason */
2333  SCIPinfoMessage(scip, NULL,
2334  ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2335  curtime, capacity, capacity - freecapacity);
2336 
2337  for( i = 0; i <= j; ++i )
2338  {
2339  if( startsolvalues[i] + durations[startindices[i]] > curtime )
2340  {
2341  SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2342  SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2343  demands[startindices[i]]);
2344  }
2345  }
2346  }
2347  break;
2348  }
2349  } /*lint --e{850}*/
2350 
2351  /* free all buffer arrays */
2352  SCIPfreeBufferArray(scip, &endindices);
2353  SCIPfreeBufferArray(scip, &startindices);
2354  SCIPfreeBufferArray(scip, &endsolvalues);
2355  SCIPfreeBufferArray(scip, &startsolvalues);
2356 
2357  return SCIP_OKAY;
2358 }
2359 
2360 /** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2361  * least zero or not. If not (*violated) is set to TRUE
2362  */
2363 static
2365  SCIP* scip, /**< SCIP data structure */
2366  SCIP_CONS* cons, /**< constraint to be checked */
2367  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2368  SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2369  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2370  )
2371 {
2372  SCIP_CONSDATA* consdata;
2373 
2374  assert(scip != NULL);
2375  assert(cons != NULL);
2376  assert(violated != NULL);
2377 
2378  SCIPdebugMessage("check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2379 
2380  consdata = SCIPconsGetData(cons);
2381  assert(consdata != NULL);
2382 
2383  /* check the cumulative condition */
2384  SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2385  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2386  violated, cons, printreason) );
2387 
2388  return SCIP_OKAY;
2389 }
2390 
2391 /**@} */
2392 
2393 /**@name Conflict analysis
2394  *
2395  * @{
2396  */
2397 
2398 /** resolves the propagation of the core time algorithm */
2399 static
2401  SCIP* scip, /**< SCIP data structure */
2402  int nvars, /**< number of start time variables (activities) */
2403  SCIP_VAR** vars, /**< array of start time variables */
2404  int* durations, /**< array of durations */
2405  int* demands, /**< array of demands */
2406  int capacity, /**< cumulative capacity */
2407  int hmin, /**< left bound of time axis to be considered (including hmin) */
2408  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2409  SCIP_VAR* infervar, /**< inference variable */
2410  int inferdemand, /**< demand of the inference variable */
2411  int inferpeak, /**< time point which causes the propagation */
2412  int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2413  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2414  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2415  int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2416  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2417  )
2418 {
2419  SCIP_VAR* var;
2420  SCIP_Bool* reported;
2421  int duration;
2422  int maxlst;
2423  int minect;
2424  int ect;
2425  int lst;
2426  int j;
2427 
2428  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
2429 
2430  SCIPdebugMessage("variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2431  SCIPvarGetName(infervar), inferdemand, inferpeak);
2432  assert(nvars > 0);
2433 
2434  /* adjusted capacity */
2435  capacity -= inferdemand;
2436  maxlst = INT_MIN;
2437  minect = INT_MAX;
2438 
2439  SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2440  BMSclearMemoryArray(reported, nvars);
2441 
2442  /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2443  * inference peak and those where the current conflict bounds provide a core at the inference peak
2444  */
2445  for( j = 0; j < nvars && capacity >= 0; ++j )
2446  {
2447  var = vars[j];
2448  assert(var != NULL);
2449 
2450  /* skip inference variable */
2451  if( var == infervar )
2452  continue;
2453 
2454  duration = durations[j];
2455  assert(duration > 0);
2456 
2457  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2458  assert(SCIPisFeasEQ(scip, SCIPvarGetUbAtIndex(var, bdchgidx, TRUE), SCIPvarGetUbAtIndex(var, bdchgidx, FALSE)));
2459  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbAtIndex(var, bdchgidx, TRUE)));
2460  assert(SCIPisFeasEQ(scip, SCIPvarGetLbAtIndex(var, bdchgidx, TRUE), SCIPvarGetLbAtIndex(var, bdchgidx, FALSE)));
2461  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbAtIndex(var, bdchgidx, TRUE)));
2462 
2463  SCIPdebugMessage("variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2465  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2466 
2467  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2468  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2469 
2470  /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2471  * that job without adding it the explanation
2472  */
2473  if( inferpeak < ect && lst <= inferpeak )
2474  {
2475  capacity -= demands[j];
2476  reported[j] = TRUE;
2477 
2478  maxlst = MAX(maxlst, lst);
2479  minect = MIN(minect, ect);
2480  assert(maxlst < minect);
2481 
2482  if( explanation != NULL )
2483  explanation[j] = TRUE;
2484 
2485  continue;
2486  }
2487 
2488  /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2489  * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2490  * not part of the conflict yet we get the global bounds back.
2491  */
2492  ect = SCIPconvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2493  lst = SCIPconvertRealToInt(scip, SCIPgetConflictVarUb(scip, var));
2494 
2495  /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2496  * of that job without and collect the job as part of the explanation
2497  *
2498  * @note we do not need to reported that job to SCIP since the required bounds are already reported
2499  */
2500  if( inferpeak < ect && lst <= inferpeak )
2501  {
2502  capacity -= demands[j];
2503  reported[j] = TRUE;
2504 
2505  maxlst = MAX(maxlst, lst);
2506  minect = MIN(minect, ect);
2507  assert(maxlst < minect);
2508 
2509  if( explanation != NULL )
2510  explanation[j] = TRUE;
2511  }
2512  }
2513 
2514  if( capacity >= 0 )
2515  {
2516  int* cands;
2517  int* canddemands;
2518  int ncands;
2519  int c;
2520 
2521  SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2522  SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2523  ncands = 0;
2524 
2525  /* collect all cores of the variables which lay in the considered time window except the inference variable */
2526  for( j = 0; j < nvars; ++j )
2527  {
2528  var = vars[j];
2529  assert(var != NULL);
2530 
2531  /* skip inference variable */
2532  if( var == infervar || reported[j] )
2533  continue;
2534 
2535  duration = durations[j];
2536  assert(duration > 0);
2537 
2538  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2539  assert(SCIPisFeasEQ(scip, SCIPvarGetUbAtIndex(var, bdchgidx, TRUE), SCIPvarGetUbAtIndex(var, bdchgidx, FALSE)));
2540  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbAtIndex(var, bdchgidx, TRUE)));
2541  assert(SCIPisFeasEQ(scip, SCIPvarGetLbAtIndex(var, bdchgidx, TRUE), SCIPvarGetLbAtIndex(var, bdchgidx, FALSE)));
2542  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbAtIndex(var, bdchgidx, TRUE)));
2543 
2544  /* collect local core information */
2545  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbAtIndex(var, bdchgidx, FALSE)) + duration;
2546  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(var, bdchgidx, FALSE));
2547 
2548  SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2549  SCIPvarGetName(var), SCIPvarGetLbAtIndex(var, bdchgidx, FALSE), SCIPvarGetUbAtIndex(var, bdchgidx, FALSE),
2550  SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2551 
2552  /* check if the inference peak is part of the core */
2553  if( inferpeak < ect && lst <= inferpeak )
2554  {
2555  cands[ncands] = j;
2556  canddemands[ncands] = demands[j];
2557  ncands++;
2558 
2559  capacity -= demands[j];
2560  }
2561  }
2562 
2563  /* sort candidates indices w.r.t. their demands */
2564  SCIPsortDownIntInt(canddemands, cands, ncands);
2565 
2566  assert(capacity < 0);
2567  assert(ncands > 0);
2568 
2569  /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2570  while( capacity + canddemands[ncands-1] < 0 )
2571  {
2572  ncands--;
2573  capacity += canddemands[ncands];
2574  assert(ncands > 0);
2575  }
2576 
2577  /* compute the size (number of time steps) of the job cores */
2578  for( c = 0; c < ncands; ++c )
2579  {
2580  var = vars[cands[c]];
2581  assert(var != NULL);
2582 
2583  duration = durations[cands[c]];
2584 
2585  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbAtIndex(var, bdchgidx, FALSE)) + duration;
2586  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(var, bdchgidx, FALSE));
2587 
2588  maxlst = MAX(maxlst, lst);
2589  minect = MIN(minect, ect);
2590  assert(maxlst < minect);
2591  }
2592 
2593  SCIPdebugMessage("infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2594  assert(inferpeak >= maxlst);
2595  assert(inferpeak < minect);
2596 
2597  /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2598  if( relaxedpeak < inferpeak )
2599  {
2600  inferpeak = MAX(maxlst, relaxedpeak);
2601  }
2602  else if( relaxedpeak > inferpeak )
2603  {
2604  inferpeak = MIN(minect-1, relaxedpeak);
2605  }
2606  assert(inferpeak >= hmin);
2607  assert(inferpeak < hmax);
2608  assert(inferpeak >= maxlst);
2609  assert(inferpeak < minect);
2610 
2611  /* post all necessary bound changes */
2612  for( c = 0; c < ncands; ++c )
2613  {
2614  var = vars[cands[c]];
2615  assert(var != NULL);
2616 
2617  if( usebdwidening )
2618  {
2619  duration = durations[cands[c]];
2620 
2621  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2622  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2623  }
2624  else
2625  {
2626  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2627  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2628  }
2629 
2630  if( explanation != NULL )
2631  explanation[cands[c]] = TRUE;
2632  }
2633 
2634  SCIPfreeBufferArray(scip, &canddemands);
2635  SCIPfreeBufferArray(scip, &cands);
2636  }
2637 
2638  SCIPfreeBufferArray(scip, &reported);
2639 
2640  if( provedpeak != NULL )
2641  *provedpeak = inferpeak;
2642 
2643  return SCIP_OKAY;
2644 }
2645 
2646 #if 0
2647 /** repropagation of edge finding algorithm simplified version from Petr Vilim only a small subset is reported such that
2648  * energy in total and for bound change is enough
2649  */
2650 static
2651 SCIP_RETCODE resolvePropagationEdgeFinding(
2652  SCIP* scip, /**< SCIP data structure */
2653  int nvars, /**< number of start time variables (activities) */
2654  SCIP_VAR** vars, /**< array of start time variables */
2655  int* durations, /**< array of durations */
2656  int hmin, /**< left bound of time axis to be considered (including hmin) */
2657  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2658  SCIP_VAR* infervar, /**< variable whose bound change is to be explained */
2659  INFERINFO inferinfo, /**< inference info containing position of correct bdchgids */
2660  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2661  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2662  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2663  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2664  )
2665 {
2666  int est;
2667  int lct;
2668  int j;
2669 
2670  /* ???????????????????? do bound widening */
2671 
2672  assert(scip != NULL);
2673  assert(nvars > 0);
2674  assert(inferInfoGetProprule(inferinfo) == PROPRULE_2_EDGEFINDING);
2675 
2676  SCIPdebugMessage("repropagate edge-finding with short reasons for variable <%s>\n", SCIPvarGetName(infervar));
2677 
2678  if( boundtype == SCIP_BOUNDTYPE_LOWER )
2679  {
2680  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
2681  }
2682  else
2683  {
2684  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
2685  }
2686 
2687  est = inferInfoGetData1(inferinfo);
2688  lct = inferInfoGetData2(inferinfo);
2689  assert(est < lct);
2690 
2691  /* collect the energies of all variables in [est_omega, lct_omega] */
2692  for( j = 0; j < nvars; ++j )
2693  {
2694  SCIP_VAR* var;
2695  SCIP_Bool left;
2696  SCIP_Bool right;
2697  int duration;
2698  int lb;
2699  int ub;
2700 
2701  var = vars[j];
2702  assert(var != NULL);
2703 
2704  if( var == infervar )
2705  {
2706  if( explanation != NULL )
2707  explanation[j] = TRUE;
2708 
2709  continue;
2710  }
2711 
2712  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbAtIndex(var, bdchgidx, FALSE));
2713  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(var, bdchgidx, FALSE));
2714 
2715  duration = durations[j];
2716  assert(duration > 0);
2717 
2718  /* in case the earliest start time is equal to hmin we have to also consider the jobs which run in that region
2719  * since we use adjusted jobs during the propagation
2720  */
2721  left = (est == hmin && lb + duration > hmin) || lb >= est;
2722 
2723  /* in case the latest completion time is equal to hmax we have to also consider the jobs which run in that region
2724  * since we use adjusted jobs during the propagation
2725  */
2726  right = (lct == hmax && ub < hmax) || ub + duration <= lct;
2727 
2728  /* store all jobs running in [est_omega; lct_omega] */
2729  if( left && right )
2730  {
2731  /* check if bound widening should be used */
2732  if( usebdwidening )
2733  {
2734  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(lct - duration)) );
2735  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(est)) );
2736  }
2737  else
2738  {
2739  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2740  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2741  }
2742 
2743  if( explanation != NULL )
2744  explanation[j] = TRUE;
2745  }
2746  }
2747 
2748  return SCIP_OKAY;
2749 }
2750 #endif
2751 
2752 /** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2753 static
2754 int computeOverlap(
2755  int begin, /**< begin of the times interval */
2756  int end, /**< end of time interval */
2757  int est, /**< earliest start time */
2758  int lst, /**< latest start time */
2759  int duration /**< duration of the job */
2760  )
2761 {
2762  int left;
2763  int right;
2764  int ect;
2765  int lct;
2766 
2767  ect = est + duration;
2768  lct = lst + duration;
2769 
2770  /* check if job runs completely within [begin,end) */
2771  if( lct <= end && est >= begin )
2772  return duration;
2773 
2774  assert(lst <= end && ect >= begin);
2775 
2776  left = ect - begin;
2777  assert(left > 0);
2778 
2779  right = end - lst;
2780  assert(right > 0);
2781 
2782  return MIN3(left, right, end - begin);
2783 }
2784 
2785 /** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2786  * reason
2787  *
2788  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2789  */
2790 static
2792  SCIP* scip, /**< SCIP data structure */
2793  int nvars, /**< number of start time variables (activities) */
2794  SCIP_VAR** vars, /**< array of start time variables */
2795  int* durations, /**< array of durations */
2796  int* demands, /**< array of demands */
2797  int capacity, /**< capacity of the cumulative condition */
2798  int begin, /**< begin of the time window */
2799  int end, /**< end of the time window */
2800  SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2801  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2802  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2803  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2804  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2805  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2806  )
2807 {
2808  int* locenergies;
2809  int* overlaps;
2810  int* idxs;
2811 
2812  int requiredenergy;
2813  int v;
2814 
2815  SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2816  SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2817  SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2818 
2819  /* energy which needs be explained */
2820  requiredenergy = (end - begin) * capacity;
2821 
2822  SCIPdebugMessage("analysis energy load in [%d,%d) (capacity %d, energy %d)\n", begin, end, capacity, requiredenergy);
2823 
2824  /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2825  * takes
2826  */
2827  for( v = 0; v < nvars; ++v )
2828  {
2829  SCIP_VAR* var;
2830  int glbenergy;
2831  int duration;
2832  int demand;
2833  int est;
2834  int lst;
2835 
2836  var = vars[v];
2837  assert(var != NULL);
2838 
2839  locenergies[v] = 0;
2840  overlaps[v] = 0;
2841  idxs[v] = v;
2842 
2843  demand = demands[v];
2844  assert(demand > 0);
2845 
2846  duration = durations[v];
2847  assert(duration > 0);
2848 
2849  /* check if the variable equals the inference variable (the one which was propagated) */
2850  if( infervar == var )
2851  {
2852  int overlap;
2853  int right;
2854  int left;
2855 
2856  assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2857 
2858  SCIPdebugMessage("inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2859  SCIPvarGetName(var), SCIPvarGetLbAtIndex(var, bdchgidx, FALSE), SCIPvarGetUbAtIndex(var, bdchgidx, FALSE),
2860  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2861 
2862  /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2863  * which is necessary from the inference variable
2864  */
2865  if( boundtype == SCIP_BOUNDTYPE_UPPER )
2866  {
2867  int lct;
2868 
2869  /* get the latest start time of the infer start time variable before the propagation took place */
2870  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(var, bdchgidx, FALSE));
2871 
2872  /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2873  * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2874  * scheduled w.r.t. its latest start time
2875  */
2876  assert(lst < end);
2877 
2878  /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2879  * interval (before the propagation)
2880  */
2881  right = MIN3(end - lst, end - begin, duration);
2882 
2883  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2884  assert(right > 0);
2885 
2886  lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2887  assert(begin <= lct);
2888  assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(var, bdchgidx, TRUE)) < begin);
2889 
2890  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2891  left = MIN(lct - begin + 1, end - begin);
2892  assert(left > 0);
2893 
2894  /* compute the minimum overlap; */
2895  overlap = MIN(left, right);
2896  assert(overlap > 0);
2897  assert(overlap <= end - begin);
2898  assert(overlap <= duration);
2899 
2900  if( usebdwidening )
2901  {
2902  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(var, bdchgidx, FALSE)) <= (end - overlap));
2903  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2904  }
2905  else
2906  {
2907  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2908  }
2909  }
2910  else
2911  {
2912  int ect;
2913 
2914  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2915 
2916  /* get the earliest completion time of the infer start time variable before the propagation took place */
2917  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbAtIndex(var, bdchgidx, FALSE)) + duration;
2918 
2919  /* the earliest start time of the inference start time variable before the propagation needs to be larger as
2920  * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
2921  * the job is scheduled w.r.t. its earliest start time
2922  */
2923  assert(ect > begin);
2924 
2925  /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
2926  * interval (before the propagation)
2927  */
2928  left = MIN3(ect - begin, end - begin, duration);
2929 
2930  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2931  assert(left > 0);
2932 
2933  est = SCIPconvertRealToInt(scip, relaxedbd);
2934  assert(end >= est);
2935  assert(bdchgidx == NULL || end - SCIPvarGetLbAtIndex(var, bdchgidx, TRUE) < duration);
2936 
2937  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2938  right = MIN(end - est + 1, end - begin);
2939  assert(right > 0);
2940 
2941  /* compute the minimum overlap */
2942  overlap = MIN(left, right);
2943  assert(overlap > 0);
2944  assert(overlap <= end - begin);
2945  assert(overlap <= duration);
2946 
2947  if( usebdwidening )
2948  {
2949  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbAtIndex(var, bdchgidx, FALSE)) >= (begin + overlap - duration));
2950  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
2951  }
2952  else
2953  {
2954  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2955  }
2956  }
2957 
2958  /* subtract the amount of energy which is available due to the overlap of the inference start time */
2959  requiredenergy -= overlap * demand;
2960 
2961  if( explanation != NULL )
2962  explanation[v] = TRUE;
2963 
2964  continue;
2965  }
2966 
2967  /* global time points */
2968  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
2969  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2970 
2971  glbenergy = 0;
2972 
2973  /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
2974  * time window
2975  */
2976  if( est + duration > begin && lst < end )
2977  {
2978  /* evaluated global contribution */
2979  glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
2980 
2981  /* remove the globally available energy form the required energy */
2982  requiredenergy -= glbenergy;
2983 
2984  if( explanation != NULL )
2985  explanation[v] = TRUE;
2986  }
2987 
2988  /* local time points */
2989  est = SCIPconvertRealToInt(scip, SCIPvarGetLbAtIndex(var, bdchgidx, FALSE));
2990  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(var, bdchgidx, FALSE));
2991 
2992  /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
2993  * time window
2994  */
2995  if( est + duration > begin && lst < end )
2996  {
2997  overlaps[v] = computeOverlap(begin, end, est, lst, duration);
2998 
2999  /* evaluated additionally local energy contribution */
3000  locenergies[v] = overlaps[v] * demand - glbenergy;
3001  assert(locenergies[v] >= 0);
3002  }
3003  }
3004 
3005  /* sort the variable contributions w.r.t. additional local energy contributions */
3006  SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3007 
3008  /* add local energy contributions until an overload is implied */
3009  for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3010  {
3011  SCIP_VAR* var;
3012  int duration;
3013  int overlap;
3014  int relaxlb;
3015  int relaxub;
3016  int idx;
3017 
3018  idx = idxs[v];
3019  assert(idx >= 0 && idx < nvars);
3020 
3021  var = vars[idx];
3022  assert(var != NULL);
3023  assert(var != infervar);
3024 
3025  duration = durations[idx];
3026  assert(duration > 0);
3027 
3028  overlap = overlaps[v];
3029  assert(overlap > 0);
3030 
3031  requiredenergy -= locenergies[v];
3032 
3033  if( requiredenergy < -1 )
3034  {
3035  int demand;
3036 
3037  demand = demands[idx];
3038  assert(demand > 0);
3039 
3040  overlap += (int)((requiredenergy + 1) / demand);
3041 
3042 #ifndef NDEBUG
3043  requiredenergy += locenergies[v];
3044  requiredenergy -= overlap * demand;
3045  assert(requiredenergy < 0);
3046 #endif
3047  }
3048  assert(overlap > 0);
3049 
3050  relaxlb = begin - duration + overlap;
3051  relaxub = end - overlap;
3052 
3053  SCIPdebugMessage("variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3054  SCIPvarGetName(var),
3057  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var),
3058  relaxlb, relaxub, demands[idx], duration);
3059 
3060  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3061  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3062 
3063  if( explanation != NULL )
3064  explanation[idx] = TRUE;
3065  }
3066 
3067  assert(requiredenergy < 0);
3068 
3069  SCIPfreeBufferArray(scip, &idxs);
3070  SCIPfreeBufferArray(scip, &overlaps);
3071  SCIPfreeBufferArray(scip, &locenergies);
3072 
3073  return SCIP_OKAY;
3074 }
3075 
3076 /** resolve propagation w.r.t. the cumulative condition */
3077 static
3079  SCIP* scip, /**< SCIP data structure */
3080  int nvars, /**< number of start time variables (activities) */
3081  SCIP_VAR** vars, /**< array of start time variables */
3082  int* durations, /**< array of durations */
3083  int* demands, /**< array of demands */
3084  int capacity, /**< cumulative capacity */
3085  int hmin, /**< left bound of time axis to be considered (including hmin) */
3086  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3087  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3088  INFERINFO inferinfo, /**< the user information */
3089  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3090  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3091  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3092  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3093  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3094  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3095  )
3096 {
3097  switch( inferInfoGetProprule(inferinfo) )
3098  {
3099  case PROPRULE_1_CORETIMES:
3100  {
3101  int inferdemand;
3102  int inferduration;
3103  int inferpos;
3104  int inferpeak;
3105  int relaxedpeak;
3106  int provedpeak;
3107 
3108  /* get the position of the inferred variable in the vars array */
3109  inferpos = inferInfoGetData1(inferinfo);
3110  if( inferpos >= nvars || vars[inferpos] != infervar )
3111  {
3112  /* find inference variable in constraint */
3113  for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3114  {}
3115  }
3116  assert(inferpos < nvars);
3117  assert(vars[inferpos] == infervar);
3118 
3119  inferdemand = demands[inferpos];
3120  inferduration = durations[inferpos];
3121 
3122  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3123  {
3124  /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3125  * the inference variable
3126  */
3127  assert(SCIPvarGetUbAtIndex(infervar, bdchgidx, FALSE) - SCIPvarGetUbAtIndex(infervar, bdchgidx, TRUE) < inferduration + 0.5);
3128 
3129  SCIPdebugMessage("variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3130  SCIPvarGetName(infervar), SCIPvarGetUbAtIndex(infervar, bdchgidx, FALSE),
3131  SCIPvarGetUbAtIndex(infervar, bdchgidx, TRUE), relaxedbd);
3132 
3133  /* get the inference peak that the time point which lead to the that propagtion */
3134  inferpeak = SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(infervar, bdchgidx, TRUE)) + inferduration;
3135  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) + inferduration;
3136 
3137  /* make sure that the relaxed peak is part of the effective horizon */
3138  relaxedpeak = MIN(relaxedpeak, hmax-1);
3139  assert(relaxedpeak >= hmin);
3140 
3141  assert(relaxedpeak >= inferpeak);
3142  }
3143  else
3144  {
3145  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3146 
3147  SCIPdebugMessage("variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3148  SCIPvarGetName(infervar), SCIPvarGetLbAtIndex(infervar, bdchgidx, FALSE),
3149  SCIPvarGetLbAtIndex(infervar, bdchgidx, TRUE), relaxedbd);
3150 
3151  /* get the time interval where the job could not be scheduled */
3152  inferpeak = SCIPconvertRealToInt(scip, SCIPvarGetLbAtIndex(infervar, bdchgidx, TRUE)) - 1;
3153  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) - 1;
3154 
3155  /* make sure that the relaxed peak is part of the effective horizon */
3156  relaxedpeak = MAX(relaxedpeak, hmin);
3157  assert(relaxedpeak < hmax);
3158 
3159  assert(relaxedpeak <= inferpeak);
3160  }
3161 
3162  /* resolves the propagation of the core time algorithm */
3163  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3164  infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3165 
3166  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3167  {
3168  if( usebdwidening )
3169  {
3170  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3171  }
3172  else
3173  {
3174  /* old upper bound of variable itself is part of the explanation */
3175  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3176  }
3177  }
3178  else
3179  {
3180  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3181 
3182  if( usebdwidening )
3183  {
3184  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3185  }
3186  else
3187  {
3188  /* old lower bound of variable itself is part of the explanation */
3189  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3190  }
3191  }
3192 
3193  if( explanation != NULL )
3194  explanation[inferpos] = TRUE;
3195 
3196  break;
3197  }
3199  case PROPRULE_3_TTEF:
3200  {
3201  int begin;
3202  int end;
3203 
3204  begin = inferInfoGetData1(inferinfo);
3205  end = inferInfoGetData2(inferinfo);
3206  assert(begin < end);
3207 
3208  begin = MAX(begin, hmin);
3209  end = MIN(end, hmax);
3210 
3211  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3212  begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3213 
3214  break;
3215  }
3216 
3217  default:
3218  SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3219  SCIPABORT();
3220  return SCIP_INVALIDDATA; /*lint !e527*/
3221  }
3222 
3223  (*result) = SCIP_SUCCESS;
3224 
3225  return SCIP_OKAY;
3226 }
3227 
3228 /**@} */
3229 
3230 
3231 /**@name Enforcement methods
3232  *
3233  * @{
3234  */
3235 
3236 /** apply all fixings which are given by the alternative bounds */
3237 static
3239  SCIP* scip, /**< SCIP data structure */
3240  SCIP_VAR** vars, /**< array of active variables */
3241  int nvars, /**< number of active variables */
3242  int* alternativelbs, /**< alternative lower bounds */
3243  int* alternativeubs, /**< alternative lower bounds */
3244  int* downlocks, /**< number of constraints with down lock participating by the computation */
3245  int* uplocks, /**< number of constraints with up lock participating by the computation */
3246  SCIP_Bool* branched /**< pointer to store if a branching was applied */
3247  )
3248 {
3249  int v;
3250 
3251  for( v = 0; v < nvars; ++v )
3252  {
3253  SCIP_VAR* var;
3254  SCIP_Real objval;
3255 
3256  var = vars[v];
3257  assert(var != NULL);
3258 
3259  objval = SCIPvarGetObj(var);
3260 
3261  if( SCIPvarGetNLocksDown(var) == downlocks[v] && !SCIPisNegative(scip, objval) )
3262  {
3263  int ub;
3264 
3265  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3266 
3267  if( alternativelbs[v] <= ub )
3268  {
3269  SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3270  (*branched) = TRUE;
3271 
3272  SCIPdebugMessage("variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3273  SCIPvarGetLbLocal(var), alternativelbs[v]);
3274 
3275  return SCIP_OKAY;
3276  }
3277  }
3278 
3279  if( SCIPvarGetNLocksUp(var) == uplocks[v] && !SCIPisPositive(scip, objval) )
3280  {
3281  int lb;
3282 
3283  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3284 
3285  if( alternativeubs[v] >= lb )
3286  {
3287  SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3288  (*branched) = TRUE;
3289 
3290  SCIPdebugMessage("variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3291  alternativeubs[v], SCIPvarGetUbLocal(var));
3292 
3293  return SCIP_OKAY;
3294  }
3295  }
3296  }
3297 
3298  return SCIP_OKAY;
3299 }
3300 
3301 /** remove the capacity requirments for all job which start at the curtime */
3302 static
3304  SCIP_CONSDATA* consdata, /**< constraint data */
3305  int curtime, /**< current point in time */
3306  int* starttimes, /**< array of start times */
3307  int* startindices, /**< permutation with respect to the start times */
3308  int* freecapacity, /**< pointer to store the resulting free capacity */
3309  int* idx, /**< pointer to index in start time array */
3310  int nvars /**< number of vars in array of starttimes and startindices */
3311  )
3312 {
3313 
3314 #if defined SCIP_DEBUG && !defined NDEBUG
3315  int oldidx;
3316  oldidx = *idx;
3317 #endif
3318 
3319  assert(idx != NULL);
3320  assert(starttimes != NULL);
3321  assert(starttimes != NULL);
3322  assert(freecapacity != NULL);
3323  assert(starttimes[*idx] == curtime);
3324  assert(consdata->demands != NULL);
3325  assert(freecapacity != idx);
3326 
3327  /* subtract all capacity needed up to this point */
3328  (*freecapacity) -= consdata->demands[startindices[*idx]];
3329 
3330  while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3331  {
3332  ++(*idx);
3333  (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3334  assert(freecapacity != idx);
3335  }
3336 #ifdef SCIP_DEBUG
3337  assert(oldidx <= *idx);
3338 #endif
3339 }
3340 
3341 /** add the capacity requirments for all job which end at the curtime */
3342 static
3343 void addEndingJobDemands(
3344  SCIP_CONSDATA* consdata, /**< constraint data */
3345  int curtime, /**< current point in time */
3346  int* endtimes, /**< array of end times */
3347  int* endindices, /**< permutation with rspect to the end times */
3348  int* freecapacity, /**< pointer to store the resulting free capacity */
3349  int* idx, /**< pointer to index in end time array */
3350  int nvars /**< number of vars in array of starttimes and startindices */
3351  )
3352 {
3353 #if defined SCIP_DEBUG && !defined NDEBUG
3354  int oldidx;
3355  oldidx = *idx;
3356 #endif
3357 
3358  /* free all capacity usages of jobs the are no longer running */
3359  while( endtimes[*idx] <= curtime && *idx < nvars)
3360  {
3361  (*freecapacity) += consdata->demands[endindices[*idx]];
3362  ++(*idx);
3363  }
3364 
3365 #ifdef SCIP_DEBUG
3366  assert(oldidx <= *idx);
3367 #endif
3368 }
3369 
3370 /** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3371 static
3373  SCIP* scip, /**< SCIP data structure */
3374  SCIP_CONSDATA* consdata, /**< constraint handler data */
3375  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3376  int* timepoint /**< pointer to store the time point of the peak */
3377  )
3378 {
3379  int* starttimes; /* stores when each job is starting */
3380  int* endtimes; /* stores when each job ends */
3381  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3382  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3383 
3384  int nvars; /* number of activities for this constraint */
3385  int freecapacity; /* remaining capacity */
3386  int curtime; /* point in time which we are just checking */
3387  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3388 
3389  int hmin;
3390  int hmax;
3391 
3392  int j;
3393 
3394  assert(consdata != NULL);
3395 
3396  nvars = consdata->nvars;
3397  assert(nvars > 0);
3398 
3399  *timepoint = consdata->hmax;
3400 
3401  assert(consdata->vars != NULL);
3402 
3403  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3404  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3405  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3406  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3407 
3408  /* create event point arrays */
3409  createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3410  starttimes, endtimes, startindices, endindices);
3411 
3412  endindex = 0;
3413  freecapacity = consdata->capacity;
3414  hmin = consdata->hmin;
3415  hmax = consdata->hmax;
3416 
3417  /* check each startpoint of a job whether the capacity is kept or not */
3418  for( j = 0; j < nvars; ++j )
3419  {
3420  curtime = starttimes[j];
3421  SCIPdebugMessage("look at %d-th job with start %d\n", j, curtime);
3422 
3423  if( curtime >= hmax )
3424  break;
3425 
3426  /* remove the capacity requirments for all job which start at the curtime */
3427  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3428 
3429  /* add the capacity requirments for all job which end at the curtime */
3430  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3431 
3432  assert(freecapacity <= consdata->capacity);
3433  assert(endindex <= nvars);
3434 
3435  /* endindex - points to the next job which will finish */
3436  /* j - points to the last job that has been released */
3437 
3438  /* if free capacity is smaller than zero, then add branching candidates */
3439  if( freecapacity < 0 && curtime >= hmin )
3440  {
3441  *timepoint = curtime;
3442  break;
3443  }
3444  } /*lint --e{850}*/
3445 
3446  /* free all buffer arrays */
3447  SCIPfreeBufferArray(scip, &endindices);
3448  SCIPfreeBufferArray(scip, &startindices);
3449  SCIPfreeBufferArray(scip, &endtimes);
3450  SCIPfreeBufferArray(scip, &starttimes);
3451 
3452  return SCIP_OKAY;
3453 }
3454 
3455 /** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3456 static
3458  SCIP* scip, /**< SCIP data structure */
3459  SCIP_CONS** conss, /**< constraints to be processed */
3460  int nconss, /**< number of constraints */
3461  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3462  int* nbranchcands /**< pointer to store the number of branching variables */
3463  )
3464 {
3465  SCIP_HASHTABLE* collectedvars;
3466  int c;
3467 
3468  assert(scip != NULL);
3469  assert(conss != NULL);
3470 
3471  /* create a hash table */
3473  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3474 
3475  assert(scip != NULL);
3476  assert(conss != NULL);
3477 
3478  for( c = 0; c < nconss; ++c )
3479  {
3480  SCIP_CONS* cons;
3481  SCIP_CONSDATA* consdata;
3482 
3483  int curtime;
3484  int j;
3485 
3486  cons = conss[c];
3487  assert(cons != NULL);
3488 
3489  if( !SCIPconsIsActive(cons) )
3490  continue;
3491 
3492  consdata = SCIPconsGetData(cons);
3493  assert(consdata != NULL);
3494 
3495  /* get point in time when capacity is exceeded */
3496  SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3497 
3498  if( curtime < consdata->hmin || curtime >= consdata->hmax )
3499  continue;
3500 
3501  /* report all variables that are running at that point in time */
3502  for( j = 0; j < consdata->nvars; ++j )
3503  {
3504  SCIP_VAR* var;
3505  int lb;
3506  int ub;
3507 
3508  var = consdata->vars[j];
3509  assert(var != NULL);
3510 
3511  /* check if the variable was already added */
3512  if( SCIPhashtableExists(collectedvars, (void*)var) )
3513  continue;
3514 
3515  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3516  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3517 
3518  if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3519  {
3520  SCIP_Real solval;
3521  SCIP_Real score;
3522 
3523  solval = SCIPgetSolVal(scip, sol, var);
3524  score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3525 
3526  SCIPdebugMessage("add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3527  SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3528  (*nbranchcands)++;
3529 
3530  SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3531  }
3532  }
3533  }
3534 
3535  SCIPhashtableFree(&collectedvars);
3536 
3537  SCIPdebugMessage("found %d branching candidates\n", *nbranchcands);
3538 
3539  return SCIP_OKAY;
3540 }
3541 
3542 /** enforcement pseudo or LP solution */
3543 static
3545  SCIP* scip, /**< SCIP data structure */
3546  SCIP_CONS** conss, /**< constraints to be processed */
3547  int nconss, /**< number of constraints */
3548  SCIP_Bool branch, /**< should branching candidates be collected */
3549  SCIP_RESULT* result /**< pointer to store the result */
3550  )
3551 {
3552  if( branch )
3553  {
3554  int nbranchcands;
3555 
3556  nbranchcands = 0;
3557  SCIP_CALL( collectBranchingCands(scip, conss, nconss, NULL, &nbranchcands) );
3558 
3559  if( nbranchcands > 0 )
3560  (*result) = SCIP_INFEASIBLE;
3561  }
3562  else
3563  {
3564  SCIP_Bool violated;
3565  int c;
3566 
3567  violated = FALSE;
3568 
3569  /* first check if a constraints is violated */
3570  for( c = 0; c < nconss && !violated; ++c )
3571  {
3572  SCIP_CONS* cons;
3573 
3574  cons = conss[c];
3575  assert(cons != NULL);
3576 
3577  SCIP_CALL( checkCons(scip, cons, NULL, &violated, FALSE) );
3578  }
3579 
3580  if( violated )
3581  (*result) = SCIP_INFEASIBLE;
3582  }
3583 
3584  return SCIP_OKAY;
3585 }
3586 
3587 /**@} */
3588 
3589 /**@name Propagation
3590  *
3591  * @{
3592  */
3593 
3594 /** check if cumulative constraint is independently of all other constraints */
3595 static
3597  SCIP* scip, /**< SCIP data structure */
3598  SCIP_CONS* cons /**< cumulative constraint */
3599  )
3600 {
3601  SCIP_CONSDATA* consdata;
3602  SCIP_VAR** vars;
3603  SCIP_Bool* downlocks;
3604  SCIP_Bool* uplocks;
3605  int nvars;
3606  int v;
3607 
3608  consdata = SCIPconsGetData(cons);
3609  assert(consdata != NULL);
3610 
3611  nvars = consdata->nvars;
3612  vars = consdata->vars;
3613  downlocks = consdata->downlocks;
3614  uplocks = consdata->uplocks;
3615 
3616  /* check if the cumulative constraint has the only locks on the involved variables */
3617  for( v = 0; v < nvars; ++v )
3618  {
3619  SCIP_VAR* var;
3620 
3621  var = vars[v];
3622  assert(var != NULL);
3623 
3624  if( SCIPvarGetNLocksDown(var) > (int)downlocks[v] || SCIPvarGetNLocksUp(var) > (int)uplocks[v] )
3625  return FALSE;
3626  }
3627 
3628  return TRUE;
3629 }
3630 
3631 /** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3632  * (dual reductions)
3633  */
3634 static
3636  SCIP* scip, /**< SCIP data structure */
3637  SCIP_CONS* cons, /**< cumulative constraint */
3638  SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3639  int* nchgbds, /**< pointer to store the number changed variable bounds */
3640  int* nfixedvars, /**< pointer to count number of fixings */
3641  int* ndelconss, /**< pointer to count number of deleted constraints */
3642  SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3643  SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3644  )
3645 {
3646  SCIP_CONSDATA* consdata;
3647  SCIP_VAR** vars;
3648  SCIP_Real* objvals;
3649  SCIP_Real* lbs;
3650  SCIP_Real* ubs;
3651  SCIP_Real timelimit;
3652  SCIP_Real memorylimit;
3653  SCIP_Bool solved;
3654  SCIP_Bool error;
3655 
3656  int ncheckconss;
3657  int nvars;
3658  int v;
3659 
3660  assert(scip != NULL);
3661  assert(!SCIPconsIsModifiable(cons));
3662  assert(SCIPgetNConss(scip) > 0);
3663 
3664  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3665  * would/could end in an implication which can lead to cutoff of the/all optimal solution
3666  */
3667  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
3668  return SCIP_OKAY;
3669 
3670  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3671  * use the locks to decide for a dual reduction using this constraint;
3672  */
3673  if( !SCIPconsIsChecked(cons) )
3674  return SCIP_OKAY;
3675 
3676  ncheckconss = SCIPgetNCheckConss(scip);
3677 
3678  /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3679  * presolved problem do nothing execpt to change the parameter settings
3680  */
3681  if( ncheckconss == 1 )
3682  {
3683  /* shrink the minimal maximum value for the conflict length */
3684  SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3685 
3686  /* use only first unique implication point */
3687  SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3688 
3689  /* do not use reconversion conflicts */
3690  SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3691 
3692  /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3693  SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3694 
3695  /* increase the number of conflicts which induce a restart */
3696  SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3697 
3698  /* weight the variable which made into a conflict */
3699  SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3700 
3701  /* do not check pseudo solution (for performance reasons) */
3702  SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3703 
3704  /* use value based history to detect a reasonable branching point */
3705  SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3706 
3707  /* turn of LP relaxation */
3708  SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3709 
3710  /* prefer the down branch in case the value based history does not suggest something */
3711  SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3712 
3713  /* accept any bound change */
3714  SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3715 
3716  /* allow for at most 10 restart, after that the value based history should be reliable */
3717  SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3718 
3719  /* set priority for depth first search to highest possible value */
3720  SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3721 
3722  return SCIP_OKAY;
3723  }
3724 
3725  consdata = SCIPconsGetData(cons);
3726  assert(consdata != NULL);
3727 
3728  /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3729  * fail on the first place
3730  */
3731  if( consdata->triedsolving )
3732  return SCIP_OKAY;
3733 
3734  /* check if constraint is independently */
3735  if( !isConsIndependently(scip, cons) )
3736  return SCIP_OKAY;
3737 
3738  /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3739  * constraint is deleted; otherwise, we want to ensure that we do not try that again
3740  */
3741  consdata->triedsolving = TRUE;
3742 
3743  SCIPdebugMessage("the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3744  SCIPconsGetName(cons), SCIPgetNVars(scip), SCIPgetNConss(scip));
3745  SCIPdebugPrintCons(scip, cons, NULL);
3746 
3747  nvars = consdata->nvars;
3748  vars = consdata->vars;
3749 
3750  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3751  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3752  SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3753 
3754  for( v = 0; v < nvars; ++v )
3755  {
3756  SCIP_VAR* var;
3757 
3758  /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3759  * array
3760  */
3761  var = vars[v];
3762  assert(var != NULL);
3763 
3764  lbs[v] = SCIPvarGetLbLocal(var);
3765  ubs[v] = SCIPvarGetUbLocal(var);
3766 
3767  objvals[v] = SCIPvarGetObj(var);
3768  }
3769 
3770  /* check whether there is enough time and memory left */
3771  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3772  if( !SCIPisInfinity(scip, timelimit) )
3773  timelimit -= SCIPgetSolvingTime(scip);
3774  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3775 
3776  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3777  if( !SCIPisInfinity(scip, memorylimit) )
3778  {
3779  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3780  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3781  }
3782 
3783  /* solve the cumulative condition separately */
3784  SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3785  consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3786 
3787  if( !(*cutoff) && !(*unbounded) && !error )
3788  {
3789  SCIP_Bool infeasible;
3790  SCIP_Bool tightened;
3791  SCIP_Bool allfixed;
3792 
3793  allfixed = TRUE;
3794 
3795  for( v = 0; v < nvars; ++v )
3796  {
3797  /* check if variable is fixed */
3798  if( lbs[v] + 0.5 > ubs[v] )
3799  {
3800  SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3801  assert(!infeasible);
3802 
3803  if( tightened )
3804  {
3805  (*nfixedvars)++;
3806  consdata->triedsolving = FALSE;
3807  }
3808  }
3809  else
3810  {
3811  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3812  assert(!infeasible);
3813 
3814  if( tightened )
3815  {
3816  (*nchgbds)++;
3817  consdata->triedsolving = FALSE;
3818  }
3819 
3820  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3821  assert(!infeasible);
3822 
3823  if( tightened )
3824  {
3825  (*nchgbds)++;
3826  consdata->triedsolving = FALSE;
3827  }
3828 
3829  allfixed = FALSE;
3830  }
3831  }
3832 
3833  /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3834  if( allfixed )
3835  {
3836  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3837  (*ndelconss)++;
3838  }
3839  }
3840 
3841  SCIPfreeBufferArray(scip, &objvals);
3842  SCIPfreeBufferArray(scip, &ubs);
3843  SCIPfreeBufferArray(scip, &lbs);
3844 
3845  return SCIP_OKAY;
3846 }
3847 
3848 /** start conflict analysis to analysis the core insertion which is infeasible */
3849 static
3851  SCIP* scip, /**< SCIP data structure */
3852  int nvars, /**< number of start time variables (activities) */
3853  SCIP_VAR** vars, /**< array of start time variables */
3854  int* durations, /**< array of durations */
3855  int* demands, /**< array of demands */
3856  int capacity, /**< cumulative capacity */
3857  int hmin, /**< left bound of time axis to be considered (including hmin) */
3858  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3859  SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3860  int inferduration, /**< duration of the start time variable */
3861  int inferdemand, /**< demand of the start time variable */
3862  int inferpeak, /**< profile preak which causes the infeasibilty */
3863  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3864  SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3865  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3866  )
3867 {
3868  SCIPdebugMessage("detected infeasibility due to adding a core to the core resource profile\n");
3869  SCIPdebugMessage("variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3870  SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3871 
3872  /* initialize conflict analysis if conflict analysis is applicable */
3874  {
3876 
3877  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3878  infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3879 
3880  SCIPdebugMessage("add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3881 
3882  /* add both bound of the inference variable since these biuld the core which we could not inserted */
3883  if( usebdwidening )
3884  {
3885  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
3886  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
3887  }
3888  else
3889  {
3890  SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
3891  SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
3892  }
3893 
3894  *initialized = TRUE;
3895  }
3896 
3897  return SCIP_OKAY;
3898 }
3899 
3900 /** We are using the core resource profile which contains all core except the one of the start time variable which we
3901  * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
3902  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
3903  * analysis
3904  */
3905 static
3907  SCIP* scip, /**< SCIP data structure */
3908  int nvars, /**< number of start time variables (activities) */
3909  SCIP_VAR** vars, /**< array of start time variables */
3910  int* durations, /**< array of durations */
3911  int* demands, /**< array of demands */
3912  int capacity, /**< cumulative capacity */
3913  int hmin, /**< left bound of time axis to be considered (including hmin) */
3914  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3915  SCIP_CONS* cons, /**< constraint which is propagated */
3916  SCIP_PROFILE* profile, /**< resource profile */
3917  int idx, /**< position of the variable to propagate */
3918  int* nchgbds, /**< pointer to store the number of bound changes */
3919  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3920  SCIP_Bool* initialized, /**< was conflict analysis initialized */
3921  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3922  SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
3923  )
3924 {
3925  SCIP_VAR* var;
3926  int ntimepoints;
3927  int duration;
3928  int demand;
3929  int peak;
3930  int newlb;
3931  int est;
3932  int lst;
3933  int pos;
3934 
3935  var = vars[idx];
3936  assert(var != NULL);
3937 
3938  duration = durations[idx];
3939  assert(duration > 0);
3940 
3941  demand = demands[idx];
3942  assert(demand > 0);
3943 
3944  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3945  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3946  ntimepoints = SCIPprofileGetNTimepoints(profile);
3947 
3948  /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
3949  * load which we have at the earliest start time (lower bound)
3950  */
3951  (void) SCIPprofileFindLeft(profile, est, &pos);
3952 
3953  SCIPdebugMessage("propagate earliest start time (lower bound) (pos %d)\n", pos);
3954 
3955  /* we now trying to move the earliest start time in steps of at most "duration" length */
3956  do
3957  {
3958  INFERINFO inferinfo;
3959  SCIP_Bool tightened;
3960  int ect;
3961 
3962 #ifndef NDEBUG
3963  {
3964  /* in debug mode we check that we adjust the search position correctly */
3965  int tmppos;
3966 
3967  (void)SCIPprofileFindLeft(profile, est, &tmppos);
3968  assert(pos == tmppos);
3969  }
3970 #endif
3971  ect = est + duration;
3972  peak = -1;
3973 
3974  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
3975  * want a peak which is closest to the earliest completion time
3976  */
3977  do
3978  {
3979  /* check if the profile load conflicts with the demand of the start time variable */
3980  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
3981  peak = pos;
3982 
3983  pos++;
3984  }
3985  while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
3986 
3987  /* if we found no peak that means current the job could be scheduled at its earliest start time without
3988  * conflicting to the core resource profile
3989  */
3990  if( peak == -1 )
3991  break;
3992 
3993  /* the peak position gives us a time point where the start time variable is in conflict with the resource
3994  * profile. That means we have to move it to the next time point in the resource profile but at most to the
3995  * earliest completion time (the remaining move will done in the next loop)
3996  */
3997  newlb = SCIPprofileGetTime(profile, peak+1);
3998  newlb = MIN(newlb, ect);
3999 
4000  /* if the earliest start time is greater than the lst we detected an infeasibilty */
4001  if( newlb > lst )
4002  {
4003  SCIPdebugMessage("variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4004 
4005  /* use conflict analysis to analysis the core insertion which was infeasible */
4006  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4007  var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4008 
4009  if( explanation != NULL )
4010  explanation[idx] = TRUE;
4011 
4012  *infeasible = TRUE;
4013 
4014  break;
4015  }
4016 
4017  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4018  * bound change
4019  */
4020  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, 0);
4021 
4022  /* perform the bound lower bound change */
4023  SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4024  assert(tightened);
4025  assert(!(*infeasible));
4026 
4027  SCIPdebugMessage("variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4028  (*nchgbds)++;
4029 
4030  /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4032 
4033  /* adjust the earliest start time
4034  *
4035  * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4036  * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4037  * involved.
4038  */
4039  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4040  assert(est >= newlb);
4041 
4042  /* adjust the search position for the resource profile for the next step */
4043  if( est == SCIPprofileGetTime(profile, peak+1) )
4044  pos = peak + 1;
4045  else
4046  pos = peak;
4047  }
4048  while( est < lst );
4049 
4050  return SCIP_OKAY;
4051 }
4052 
4053 /** We are using the core resource profile which contains all core except the one of the start time variable which we
4054  * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4055  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4056  * analysis
4057  */
4058 static
4060  SCIP* scip, /**< SCIP data structure */
4061  SCIP_VAR* var, /**< start time variable to propagate */
4062  int duration, /**< duration of the job */
4063  int demand, /**< demand of the job */
4064  int capacity, /**< cumulative capacity */
4065  SCIP_CONS* cons, /**< constraint which is propagated */
4066  SCIP_PROFILE* profile, /**< resource profile */
4067  int idx, /**< position of the variable to propagate */
4068  int* nchgbds /**< pointer to store the number of bound changes */
4069  )
4070 {
4071  int ntimepoints;
4072  int newub;
4073  int peak;
4074  int pos;
4075  int est;
4076  int lst;
4077  int lct;
4078 
4079  assert(var != NULL);
4080  assert(duration > 0);
4081  assert(demand > 0);
4082 
4083  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4084  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4085 
4086  /* in case the start time variable is fixed do nothing */
4087  if( est == lst )
4088  return SCIP_OKAY;
4089 
4090  ntimepoints = SCIPprofileGetNTimepoints(profile);
4091 
4092  lct = lst + duration;
4093 
4094  /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4095  * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4096  * position gives us the load which we have at the latest completion time minus one
4097  */
4098  (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4099 
4100  SCIPdebugMessage("propagate upper bound (pos %d)\n", pos);
4101  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
4102 
4103  if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4104  return SCIP_OKAY;
4105 
4106  /* we now trying to move the latest start time in steps of at most "duration" length */
4107  do
4108  {
4109  INFERINFO inferinfo;
4110  SCIP_Bool tightened;
4111  SCIP_Bool infeasible;
4112 
4113  peak = -1;
4114 
4115 #ifndef NDEBUG
4116  {
4117  /* in debug mode we check that we adjust the search position correctly */
4118  int tmppos;
4119 
4120  (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4121  assert(pos == tmppos);
4122  }
4123 #endif
4124 
4125  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4126  * want a peak which is closest to the latest start time
4127  */
4128  do
4129  {
4130  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4131  peak = pos;
4132 
4133  pos--;
4134  }
4135  while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4136 
4137  /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4138  * to the core resource profile
4139  */
4140  if( peak == -1 )
4141  break;
4142 
4143  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4144  * profile. That means the job has be done until that point. Hence that gives us the latest completion
4145  * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4146  * doing in the next loop)
4147  */
4148  newub = SCIPprofileGetTime(profile, peak);
4149  newub = MAX(newub, lst) - duration;
4150  assert(newub >= est);
4151 
4152  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4153  * bound change
4154  */
4155  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, 0);
4156 
4157  /* perform the bound upper bound change */
4158  SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4159  assert(tightened);
4160  assert(!infeasible);
4161 
4162  SCIPdebugMessage("variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4163  (*nchgbds)++;
4164 
4165  /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4167 
4168  /* adjust the latest start and completion time
4169  *
4170  * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4171  * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4172  * involved.
4173  */
4174  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4175  assert(lst <= newub);
4176  lct = lst + duration;
4177 
4178  /* adjust the search position for the resource profile for the next step */
4179  if( SCIPprofileGetTime(profile, peak) == lct )
4180  pos = peak - 1;
4181  else
4182  pos = peak;
4183  }
4184  while( est < lst );
4185 
4186  return SCIP_OKAY;
4187 }
4188 
4189 /** compute for the different earliest start and latest completion time the core energy of the corresponding time
4190  * points
4191  */
4192 static
4194  SCIP* scip, /**< SCIP data structure */
4195  SCIP_PROFILE* profile, /**< core profile */
4196  int nvars, /**< number of start time variables (activities) */
4197  int* ests, /**< array of sorted earliest start times */
4198  int* lcts, /**< array of sorted latest completion times */
4199  int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4200  int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4201  )
4202 {
4203  int ntimepoints;
4204  int energy;
4205  int t;
4206  int v;
4207 
4208  ntimepoints = SCIPprofileGetNTimepoints(profile);
4209  t = ntimepoints - 1;
4210  energy = 0;
4211 
4212  /* compute core energy after the earliest start time of each job */
4213  for( v = nvars-1; v >= 0; --v )
4214  {
4215  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4216  {
4217  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4218  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4219  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4220  t--;
4221  }
4222  assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4223 
4224  /* maybe ests[j] is in-between two timepoints */
4225  if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4226  {
4227  assert(t > 0);
4228  coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4229  }
4230  else
4231  coreEnergyAfterEst[v] = energy;
4232  }
4233 
4234  t = ntimepoints - 1;
4235  energy = 0;
4236 
4237  /* compute core energy after the latest completion time of each job */
4238  for( v = nvars-1; v >= 0; --v )
4239  {
4240  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4241  {
4242  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4243  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4244  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4245  t--;
4246  }
4247  assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4248 
4249  /* maybe lcts[j] is in-between two timepoints */
4250  if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4251  {
4252  assert(t > 0);
4253  coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4254  }
4255  else
4256  coreEnergyAfterLct[v] = energy;
4257  }
4258 
4259  return SCIP_OKAY;
4260 }
4261 
4262 /** collect earliest start times, latest completion time, and free energy contributions */
4263 static
4264 void collectDataTTEF(
4265  SCIP* scip, /**< SCIP data structure */
4266  int nvars, /**< number of start time variables (activities) */
4267  SCIP_VAR** vars, /**< array of start time variables */
4268  int* durations, /**< array of durations */
4269  int* demands, /**< array of demands */
4270  int hmin, /**< left bound of time axis to be considered (including hmin) */
4271  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4272  int* permests, /**< array to store the variable positions */
4273  int* ests, /**< array to store earliest start times */
4274  int* permlcts, /**< array to store the variable positions */
4275  int* lcts, /**< array to store latest completion times */
4276  int* ects, /**< array to store earliest completion times of the flexible part of the job */
4277  int* lsts, /**< array to store latest start times of the flexible part of the job */
4278  int* flexenergies /**< array to store the flexible energies of each job */
4279  )
4280 {
4281  int v;
4282 
4283  for( v = 0; v < nvars; ++ v)
4284  {
4285  int duration;
4286  int leftadjust;
4287  int rightadjust;
4288  int core;
4289  int est;
4290  int lct;
4291  int ect;
4292  int lst;
4293 
4294  duration = durations[v];
4295  assert(duration > 0);
4296 
4297  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4298  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
4299  ect = est + duration;
4300  lct = lst + duration;
4301 
4302  ests[v] = est;
4303  lcts[v] = lct;
4304  permests[v] = v;
4305  permlcts[v] = v;
4306 
4307  /* compute core time window which lies within the effective horizon */
4308  core = computeCoreWithInterval(hmin, hmax, ect, lst);
4309 
4310  /* compute the number of time steps the job could run before the effective horizon */
4311  leftadjust = MAX(0, hmin - est);
4312 
4313  /* compute the number of time steps the job could run after the effective horizon */
4314  rightadjust = MAX(0, lct - hmax);
4315 
4316  /* compute for each job the energy which is flexible; meaning not part of the core */
4317  flexenergies[v] = duration - leftadjust - rightadjust - core;
4318  flexenergies[v] = MAX(0, flexenergies[v]);
4319  flexenergies[v] *= demands[v];
4320  assert(flexenergies[v] >= 0);
4321 
4322  /* the earliest completion time of the flexible energy */
4323  ects[v] = MIN(ect, lst);
4324 
4325  /* the latest start time of the flexible energy */
4326  lsts[v] = MAX(ect, lst);
4327  }
4328 }
4329 
4330 /** try to tighten the lower bound of the given variable */
4331 static
4333  SCIP* scip, /**< SCIP data structure */
4334  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4335  int nvars, /**< number of start time variables (activities) */
4336  SCIP_VAR** vars, /**< array of start time variables */
4337  int* durations, /**< array of durations */
4338  int* demands, /**< array of demands */
4339  int capacity, /**< cumulative capacity */
4340  int hmin, /**< left bound of time axis to be considered (including hmin) */
4341  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4342  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4343  int duration, /**< duration of the job */
4344  int demand, /**< demand of the job */
4345  int est, /**< earliest start time of the job */
4346  int ect, /**< earliest completion time of the flexible part of the job */
4347  int lct, /**< latest completion time of the job */
4348  int begin, /**< begin of the time window under investigation */
4349  int end, /**< end of the time window under investigation */
4350  int energy, /**< available energy for the flexible part of the hob within the time window */
4351  int* bestlb, /**< pointer to strope the best lower bound change */
4352  int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4353  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4354  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4355  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4356  )
4357 {
4358  int newlb;
4359 
4360  assert(begin >= hmin);
4361  assert(end <= hmax);
4362 
4363  /* check if the time-table edge-finding should infer bounds */
4364  if( !conshdlrdata->ttefinfer )
4365  return SCIP_OKAY;
4366 
4367  /* if the job can be processed completely before or after the time window, nothing can be tightened */
4368  if( est >= end || ect <= begin )
4369  return SCIP_OKAY;
4370 
4371  /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4372  * skip since the overload check will do the job
4373  */
4374  if( est >= begin && ect <= end )
4375  return SCIP_OKAY;
4376 
4377  /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4378  * earliest start time
4379  */
4380  if( energy >= demand * (MAX(begin, est) - MIN(end, ect)) )
4381  return SCIP_OKAY;
4382 
4383  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4384  * present; therefore, we need to add the core;
4385  *
4386  * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4387  * compute the earliest completion time of the (whole) job
4388  */
4389  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4390 
4391  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4392  *
4393  * @note we can round down the compute duration w.r.t. the available energy
4394  */
4395  newlb = end - energy / demand;
4396 
4397  /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4398  * bound (latest start time); meaning it is not possible to schedule the job
4399  */
4400  if( newlb > lct - duration )
4401  {
4402  /* initialize conflict analysis if conflict analysis is applicable */
4404  {
4405  SCIP_Real relaxedbd;
4406 
4407  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4408 
4409  /* it is enough to overshoot the upper bound of the variable by one */
4410  relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4411 
4412  /* initialize conflict analysis */
4414 
4415  /* added to upper bound (which was overcut be new lower bound) of the variable */
4416  SCIP_CALL( SCIPaddConflictUb(scip, var, NULL) );
4417 
4418  /* analyze the infeasible */
4419  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4420  begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4421 
4422  (*initialized) = TRUE;
4423  }
4424 
4425  (*cutoff) = TRUE;
4426  }
4427  else if( newlb > (*bestlb) )
4428  {
4429  INFERINFO inferinfo;
4430 
4431  assert(newlb > begin);
4432 
4433  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4434 
4435  /* construct inference information */
4436  (*inferinfos) = inferInfoToInt(inferinfo);
4437  (*bestlb) = newlb;
4438  }
4439 
4440  return SCIP_OKAY;
4441 }
4442 
4443 /** try to tighten the upper bound of the given variable */
4444 static
4446  SCIP* scip, /**< SCIP data structure */
4447  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4448  int nvars, /**< number of start time variables (activities) */
4449  SCIP_VAR** vars, /**< array of start time variables */
4450  int* durations, /**< array of durations */
4451  int* demands, /**< array of demands */
4452  int capacity, /**< cumulative capacity */
4453  int hmin, /**< left bound of time axis to be considered (including hmin) */
4454  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4455  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4456  int duration, /**< duration of the job */
4457  int demand, /**< demand of the job */
4458  int est, /**< earliest start time of the job */
4459  int lst, /**< latest start time of the flexible part of the job */
4460  int lct, /**< latest completion time of the job */
4461  int begin, /**< begin of the time window under investigation */
4462  int end, /**< end of the time window under investigation */
4463  int energy, /**< available energy for the flexible part of the hob within the time window */
4464  int* bestub, /**< pointer to strope the best upper bound change */
4465  int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4466  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4467  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4468  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4469  )
4470 {
4471  int newub;
4472 
4473  assert(begin >= hmin);
4474  assert(end <= hmax);
4475  assert(est < begin);
4476 
4477  /* check if the time-table edge-finding should infer bounds */
4478  if( !conshdlrdata->ttefinfer )
4479  return SCIP_OKAY;
4480 
4481  /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4482  if( lst >= end || lct <= begin )
4483  return SCIP_OKAY;
4484 
4485  /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4486  * skip since the overload check will do the job
4487  */
4488  if( lst >= begin && lct <= end )
4489  return SCIP_OKAY;
4490 
4491  /* check if the available energy in the time window is to small to handle the flexible part of the job */
4492  if( energy >= demand * (MIN(end, lct) - MAX(begin, lst)) )
4493  return SCIP_OKAY;
4494 
4495  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4496  * present; therefore, we need to add the core;
4497  *
4498  * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4499  * latest start of the (whole) job
4500  */
4501  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4502  assert(energy >= 0);
4503 
4504  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4505  *
4506  * @note we can round down the compute duration w.r.t. the available energy
4507  */
4508  assert(demand > 0);
4509  newub = begin - duration + energy / demand;
4510 
4511  /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4512  * bound (earliest start time); meaning it is not possible to schedule the job
4513  */
4514  if( newub < est )
4515  {
4516  /* initialize conflict analysis if conflict analysis is applicable */
4518  {
4519  SCIP_Real relaxedbd;
4520 
4521  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4522 
4523  /* it is enough to undershoot the lower bound of the variable by one */
4524  relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4525 
4526  /* initialize conflict analysis */
4528 
4529  /* added to lower bound (which was undercut be new upper bound) of the variable */
4530  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
4531 
4532  /* analyze the infeasible */
4533  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4534  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4535 
4536  (*initialized) = TRUE;
4537  }
4538 
4539  (*cutoff) = TRUE;
4540  }
4541  else if( newub < (*bestub) )
4542  {
4543  INFERINFO inferinfo;
4544 
4545  assert(newub < begin);
4546 
4547  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4548 
4549  /* construct inference information */
4550  (*inferinfos) = inferInfoToInt(inferinfo);
4551  (*bestub) = newub;
4552  }
4553 
4554  return SCIP_OKAY;
4555 }
4556 
4557 /** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4558 static
4560  SCIP* scip, /**< SCIP data structure */
4561  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4562  int nvars, /**< number of start time variables (activities) */
4563  SCIP_VAR** vars, /**< array of start time variables */
4564  int* durations, /**< array of durations */
4565  int* demands, /**< array of demands */
4566  int capacity, /**< cumulative capacity */
4567  int hmin, /**< left bound of time axis to be considered (including hmin) */
4568  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4569  int* newlbs, /**< array to buffer new lower bounds */
4570  int* newubs, /**< array to buffer new upper bounds */
4571  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4572  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4573  int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4574  int* flexenergies, /**< array of flexible energies in the same order as the variables */
4575  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4576  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4577  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4578  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4579  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4580  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4581  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4582  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4583  )
4584 {
4585  int coreEnergyAfterEnd;
4586  int maxavailable;
4587  int minavailable;
4588  int totalenergy;
4589  int nests;
4590  int est;
4591  int lct;
4592  int start;
4593  int end;
4594  int v;
4595 
4596  est = INT_MAX;
4597  lct = INT_MIN;
4598 
4599  /* compute earliest start and latest completion time of all jobs */
4600  for( v = 0; v < nvars; ++v )
4601  {
4602  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4603  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4604 
4605  est = MIN(est, start);
4606  lct = MAX(lct, end);
4607  }
4608 
4609  /* adjust the effective time horizon */
4610  hmin = MAX(hmin, est);
4611  hmax = MIN(hmax, lct);
4612 
4613  end = hmax + 1;
4614  coreEnergyAfterEnd = -1;
4615 
4616  maxavailable = (hmax - hmin) * capacity;
4617  minavailable = maxavailable;
4618  totalenergy = computeTotalEnergy(durations, demands, nvars);
4619 
4620  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4621  if( (lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4622  return SCIP_OKAY;
4623 
4624  nests = nvars;
4625 
4626  /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4627  * times define the end of the time interval under investigation
4628  */
4629  for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4630  {
4631  int flexenergy;
4632  int minbegin;
4633  int lbenergy;
4634  int lbcand;
4635  int i;
4636 
4637  lct = lcts[v];
4638 
4639  /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4640  * infinity capacity is available; hence we skip that
4641  */
4642  if( lct > hmax )
4643  continue;
4644 
4645  /* if the latest completion time is smaller then hmin we have to stop */
4646  if( lct <= hmin )
4647  {
4648  assert(v == 0 || lcts[v-1] <= lcts[v]);
4649  break;
4650  }
4651 
4652  /* if the latest completion time equals to previous end time, we can continue since this particular interval
4653  * induced by end was just analyzed
4654  */
4655  if( lct == end )
4656  continue;
4657 
4658  assert(lct < end);
4659 
4660  /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4661  * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4662  * free energy; if so it means that in the next iterate the free-energy cannot be negative
4663  */
4664  if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4665  {
4666  int freeenergy;
4667 
4668  assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4669  assert(coreEnergyAfterEnd >= 0);
4670 
4671  /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4672  freeenergy = capacity * (end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4673 
4674  if( freeenergy <= minavailable )
4675  {
4676  SCIPdebugMessage("skip latest completion time <%d> (minimum available energy <%d>, free energy <%d>)\n", lct, minavailable, freeenergy);
4677  continue;
4678  }
4679  }
4680 
4681  SCIPdebugMessage("check intervals ending with <%d>\n", lct);
4682 
4683  end = lct;
4684  coreEnergyAfterEnd = coreEnergyAfterLct[v];
4685 
4686  flexenergy = 0;
4687  minavailable = maxavailable;
4688  minbegin = hmax;
4689  lbcand = -1;
4690  lbenergy = 0;
4691 
4692  /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4693  * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4694  * wider
4695  */
4696  for( i = nests-1; i >= 0; --i )
4697  {
4698  SCIP_VAR* var;
4699  int freeenergy;
4700  int duration;
4701  int demand;
4702  int begin;
4703  int idx;
4704  int lst;
4705 
4706  idx = perm[i];
4707  assert(idx >= 0);
4708  assert(idx < nvars);
4709  assert(!(*cutoff));
4710 
4711  /* the earliest start time of the job */
4712  est = ests[i];
4713 
4714  /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4715  * latest completion times (which define end) are scant in non-increasing order
4716  */
4717  if( end <= est )
4718  {
4719  nests--;
4720  continue;
4721  }
4722 
4723  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4724  * current ending time
4725  */
4726  if( (end - est) * capacity >= totalenergy )
4727  break;
4728 
4729  var = vars[idx];
4730  assert(var != NULL);
4731 
4732  duration = durations[idx];
4733  assert(duration > 0);
4734 
4735  demand = demands[idx];
4736  assert(demand > 0);
4737 
4738  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4739 
4740  /* the latest start time of the free part of the job */
4741  lst = lsts[idx];
4742 
4743  /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4744  * investigation; hence the overload check will do the the job
4745  */
4746  assert(est <= minbegin);
4747  if( minavailable < maxavailable && est < minbegin )
4748  {
4749  assert(!(*cutoff));
4750 
4751  /* try to tighten the upper bound */
4752  SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4753  var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4754  initialized, explanation, cutoff) );
4755 
4756  if( *cutoff )
4757  break;
4758  }
4759 
4760  SCIPdebugMessage("check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4761  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4762 
4763  begin = est;
4764  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4765 
4766  /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4767  * free energy
4768  */
4769  if( begin < hmin )
4770  break;
4771 
4772  /* compute the contribution to the flexible energy */
4773  if( lct <= end )
4774  {
4775  /* if the jobs has to finish before the end, all the energy has to be scheduled */
4776  assert(lst >= begin);
4777  assert(flexenergies[idx] >= 0);
4778  flexenergy += flexenergies[idx];
4779  }
4780  else
4781  {
4782  /* the job partly overlaps with the end */
4783  int candenergy;
4784  int energy;
4785 
4786  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4787  * w.r.t. latest start time
4788  *
4789  * @note we need to be aware of the effective horizon
4790  */
4791  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4792  assert(end - lst < duration);
4793  assert(energy >= 0);
4794 
4795  /* adjust the flexible energy of the time interval */
4796  flexenergy += energy;
4797 
4798  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4799  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4800  assert(candenergy >= 0);
4801 
4802  /* check if we found a better candidate */
4803  if( candenergy > lbenergy )
4804  {
4805  lbenergy = candenergy;
4806  lbcand = idx;
4807  }
4808  }
4809 
4810  SCIPdebugMessage("time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4811  assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4812 
4813  /* compute the energy which is not used yet */
4814  freeenergy = capacity * (end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4815 
4816  /* check overload */
4817  if( freeenergy < 0 )
4818  {
4819  SCIPdebugMessage("analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4820 
4821  /* initialize conflict analysis if conflict analysis is applicable */
4823  {
4824  /* analyze infeasibilty */
4826 
4827  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4828  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
4829  conshdlrdata->usebdwidening, explanation) );
4830 
4831  (*initialized) = TRUE;
4832  }
4833 
4834  (*cutoff) = TRUE;
4835 
4836  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4837  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
4838 
4839  break;
4840  }
4841 
4842  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4843  if( lbenergy > 0 && freeenergy < lbenergy )
4844  {
4845  int energy;
4846  int newlb;
4847  int ect;
4848 
4849  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4850  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4851 
4852  /* remove the energy of our job from the ... */
4853  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, end - lsts[lbcand])) * demands[lbcand];
4854 
4855  newlb = end - (int)(energy / demands[lbcand]);
4856 
4857  if( newlb > lst )
4858  {
4859  /* initialize conflict analysis if conflict analysis is applicable */
4861  {
4862  SCIP_Real relaxedbd;
4863 
4864  /* analyze infeasibilty */
4866 
4867  relaxedbd = lst + 1.0;
4868 
4869  /* added to upper bound (which was overcut be new lower bound) of the variable */
4870  SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4871 
4872  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4873  begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
4874  conshdlrdata->usebdwidening, explanation) );
4875 
4876  (*initialized) = TRUE;
4877  }
4878 
4879  (*cutoff) = TRUE;
4880  break;
4881  }
4882  else if( newlb > newlbs[lbcand] )
4883  {
4884  INFERINFO inferinfo;
4885 
4886  /* construct inference information */
4887  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4888 
4889  /* buffer upper bound change */
4890  lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
4891  newlbs[lbcand] = newlb;
4892  }
4893  }
4894 
4895  /* check if the current interval has a smaller free energy */
4896  if( minavailable > freeenergy )
4897  {
4898  minavailable = freeenergy;
4899  minbegin = begin;
4900  }
4901  assert(minavailable >= 0);
4902  }
4903  }
4904 
4905  return SCIP_OKAY;
4906 }
4907 
4908 /** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
4909 static
4911  SCIP* scip, /**< SCIP data structure */
4912  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4913  int nvars, /**< number of start time variables (activities) */
4914  SCIP_VAR** vars, /**< array of start time variables */
4915  int* durations, /**< array of durations */
4916  int* demands, /**< array of demands */
4917  int capacity, /**< cumulative capacity */
4918  int hmin, /**< left bound of time axis to be considered (including hmin) */
4919  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4920  int* newlbs, /**< array to buffer new lower bounds */
4921  int* newubs, /**< array to buffer new upper bounds */
4922  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4923  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4924  int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
4925  int* flexenergies, /**< array of flexible energies in the same order as the variables */
4926  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
4927  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4928  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4929  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4930  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4931  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4932  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4933  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4934  )
4935 {
4936  int coreEnergyAfterStart;
4937  int maxavailable;
4938  int minavailable;
4939  int totalenergy;
4940  int nlcts;
4941  int begin;
4942  int minest;
4943  int maxlct;
4944  int start;
4945  int end;
4946  int v;
4947 
4948  if( *cutoff )
4949  return SCIP_OKAY;
4950 
4951  begin = hmin - 1;
4952  coreEnergyAfterStart = -1;
4953 
4954  minest = INT_MAX;
4955  maxlct = INT_MIN;
4956 
4957  /* compute earliest start and latest completion time of all jobs */
4958  for( v = 0; v < nvars; ++v )
4959  {
4960  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4961  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4962 
4963  minest = MIN(minest, start);
4964  maxlct = MAX(maxlct, end);
4965  }
4966 
4967  /* adjust the effective time horizon */
4968  hmin = MAX(hmin, minest);
4969  hmax = MIN(hmax, maxlct);
4970 
4971  maxavailable = (hmax - hmin) * capacity;
4972  minavailable = maxavailable;
4973  totalenergy = computeTotalEnergy(durations, demands, nvars);
4974 
4975  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4976  if( (lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4977  return SCIP_OKAY;
4978 
4979  nlcts = 0;
4980 
4981  /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
4982  * define the start of the time interval under investigation
4983  */
4984  for( v = 0; v < nvars; ++v )
4985  {
4986  int flexenergy;
4987  int minend;
4988  int ubenergy;
4989  int ubcand;
4990  int est;
4991  int i;
4992 
4993  est = ests[v];
4994 
4995  /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
4996  * infinity capacity is available; hence we skip that
4997  */
4998  if( est < hmin )
4999  continue;
5000 
5001  /* if the earliest start time is larger or equal then hmax we have to stop */
5002  if( est >= hmax )
5003  break;
5004 
5005  /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5006  * induced by start was just analyzed
5007  */
5008  if( est == begin )
5009  continue;
5010 
5011  assert(est > begin);
5012 
5013  SCIPdebugMessage("check intervals starting with <%d>\n", est);
5014 
5015  begin = est;
5016  coreEnergyAfterStart = coreEnergyAfterEst[v];
5017 
5018  flexenergy = 0;
5019  minavailable = maxavailable;
5020  minend = hmin;
5021  ubcand = -1;
5022  ubenergy = 0;
5023 
5024  /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5025  * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5026  */
5027  for( i = nlcts; i < nvars; ++i )
5028  {
5029  SCIP_VAR* var;
5030  int freeenergy;
5031  int duration;
5032  int demand;
5033  int idx;
5034  int lct;
5035  int ect;
5036 
5037  idx = perm[i];
5038  assert(idx >= 0);
5039  assert(idx < nvars);
5040  assert(!(*cutoff));
5041 
5042  /* the earliest start time of the job */
5043  lct = lcts[i];
5044 
5045  /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5046  * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5047  */
5048  if( lct <= begin )
5049  {
5050  nlcts++;
5051  continue;
5052  }
5053 
5054  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5055  * start with current beginning time
5056  */
5057  if( (lct - begin) * capacity >= totalenergy )
5058  break;
5059 
5060  var = vars[idx];
5061  assert(var != NULL);
5062 
5063  duration = durations[idx];
5064  assert(duration > 0);
5065 
5066  demand = demands[idx];
5067  assert(demand > 0);
5068 
5069  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5070 
5071  /* the earliest completion time of the flexible part of the job */
5072  ect = ects[idx];
5073 
5074  /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5075  * investigation; hence the overload check will do the the job
5076  */
5077  assert(lct >= minend);
5078  if( minavailable < maxavailable && lct > minend )
5079  {
5080  assert(!(*cutoff));
5081 
5082  /* try to tighten the upper bound */
5083  SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5084  var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5085  initialized, explanation, cutoff) );
5086 
5087  if( *cutoff )
5088  return SCIP_OKAY;
5089  }
5090 
5091  SCIPdebugMessage("check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5092  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5093 
5094  end = lct;
5095  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5096 
5097  /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5098  * free energy
5099  */
5100  if( end > hmax )
5101  break;
5102 
5103  /* compute the contribution to the flexible energy */
5104  if( est >= begin )
5105  {
5106  /* if the jobs has to finish before the end, all the energy has to be scheduled */
5107  assert(ect <= end);
5108  assert(flexenergies[idx] >= 0);
5109  flexenergy += flexenergies[idx];
5110  }
5111  else
5112  {
5113  /* the job partly overlaps with the end */
5114  int candenergy;
5115  int energy;
5116 
5117  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5118  * w.r.t. latest start time
5119  *
5120  * @note we need to be aware of the effective horizon
5121  */
5122  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5123  assert(ect - begin < duration);
5124  assert(energy >= 0);
5125 
5126  /* adjust the flexible energy of the time interval */
5127  flexenergy += energy;
5128 
5129  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5130  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5131  assert(candenergy >= 0);
5132 
5133  /* check if we found a better candidate */
5134  if( candenergy > ubenergy )
5135  {
5136  ubenergy = candenergy;
5137  ubcand = idx;
5138  }
5139  }
5140 
5141  SCIPdebugMessage("time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5142  assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5143 
5144  /* compute the energy which is not used yet */
5145  freeenergy = capacity * (end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5146 
5147  /* check overload */
5148  if( freeenergy < 0 )
5149  {
5150  SCIPdebugMessage("analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5151 
5152  /* initialize conflict analysis if conflict analysis is applicable */
5154  {
5155  /* analyze infeasibilty */
5157 
5158  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5159  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
5160  conshdlrdata->usebdwidening, explanation) );
5161 
5162  (*initialized) = TRUE;
5163  }
5164 
5165  (*cutoff) = TRUE;
5166 
5167  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5168  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5169 
5170  return SCIP_OKAY;
5171  }
5172 
5173  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5174  if( ubenergy > 0 && freeenergy < ubenergy )
5175  {
5176  int energy;
5177  int newub;
5178  int lst;
5179 
5180  duration = durations[ubcand];
5181  assert(duration > 0);
5182 
5183  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5184  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5185 
5186  /* remove the energy of our job from the ... */
5187  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, ects[ubcand] - begin)) * demands[ubcand];
5188 
5189  newub = begin - duration + (int)(energy / demands[ubcand]);
5190 
5191  if( newub < ect - duration )
5192  {
5193  /* initialize conflict analysis if conflict analysis is applicable */
5195  {
5196  SCIP_Real relaxedbd;
5197  /* analyze infeasibilty */
5199 
5200  relaxedbd = ect - duration - 1.0;
5201 
5202  /* added to lower bound (which was undercut be new upper bound) of the variable */
5203  SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5204 
5205  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5206  begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5207  conshdlrdata->usebdwidening, explanation) );
5208 
5209  (*initialized) = TRUE;
5210  }
5211 
5212  (*cutoff) = TRUE;
5213  return SCIP_OKAY;
5214  }
5215  else if( newub < newubs[ubcand] )
5216  {
5217  INFERINFO inferinfo;
5218 
5219  /* construct inference information */
5220  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5221 
5222  /* buffer upper bound change */
5223  ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5224  newubs[ubcand] = newub;
5225  }
5226  }
5227 
5228  /* check if the current interval has a smaller free energy */
5229  if( minavailable > freeenergy )
5230  {
5231  minavailable = freeenergy;
5232  minend = end;
5233  }
5234  assert(minavailable >= 0);
5235  }
5236  }
5237 
5238  return SCIP_OKAY;
5239 }
5240 
5241 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5242  * edge-finding
5243  *
5244  * @note The algorithm is based on the following two papers:
5245  * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5246  * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5247  * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5248  * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5249  * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5250  */
5251 static
5253  SCIP* scip, /**< SCIP data structure */
5254  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5255  SCIP_PROFILE* profile, /**< current core profile */
5256  int nvars, /**< number of start time variables (activities) */
5257  SCIP_VAR** vars, /**< array of start time variables */
5258  int* durations, /**< array of durations */
5259  int* demands, /**< array of demands */
5260  int capacity, /**< cumulative capacity */
5261  int hmin, /**< left bound of time axis to be considered (including hmin) */
5262  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5263  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5264  int* nchgbds, /**< pointer to store the number of bound changes */
5265  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5266  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5267  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5268  )
5269 {
5270  int* coreEnergyAfterEst;
5271  int* coreEnergyAfterLct;
5272  int* flexenergies;
5273  int* permests;
5274  int* permlcts;
5275  int* lcts;
5276  int* ests;
5277  int* ects;
5278  int* lsts;
5279 
5280  int* newlbs;
5281  int* newubs;
5282  int* lbinferinfos;
5283  int* ubinferinfos;
5284 
5285  int v;
5286 
5287  /* check if a cutoff was already detected */
5288  if( (*cutoff) )
5289  return SCIP_OKAY;
5290 
5291  /* check if at least the basic overload checking should be perfomed */
5292  if( !conshdlrdata->ttefcheck )
5293  return SCIP_OKAY;
5294 
5295  SCIPdebugMessage("run time-table edge-finding overload checking\n");
5296 
5297  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5298  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5299  SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5300  SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5301  SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5302  SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5303  SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5304  SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5305  SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5306 
5307  SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5308  SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5309  SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5310  SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5311 
5312  /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5313  for( v = 0; v < nvars; ++v )
5314  {
5315  newlbs[v] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5316  newubs[v] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5317  lbinferinfos[v] = 0;
5318  ubinferinfos[v] = 0;
5319  }
5320 
5321  /* collect earliest start times, latest completion time, and free energy contributions */
5322  collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5323 
5324  /* sort the earliest start times and latest completion in non-decreasing order */
5325  SCIPsortIntInt(ests, permests, nvars);
5326  SCIPsortIntInt(lcts, permlcts, nvars);
5327 
5328  /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5329  * points
5330  */
5331  SCIP_CALL( computeCoreEngeryAfter(scip, profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct) );
5332 
5333  /* propagate the upper bounds and "opportunistically" the lower bounds */
5334  SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5335  newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5336  permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5337 
5338  /* propagate the lower bounds and "opportunistically" the upper bounds */
5339  SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5340  newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5341  permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5342 
5343  /* apply the buffer bound changes */
5344  for( v = 0; v < nvars && !(*cutoff); ++v )
5345  {
5346  SCIP_Bool infeasible;
5347  SCIP_Bool tightened;
5348 
5349  SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v], TRUE, &infeasible, &tightened) );
5350 
5351  /* since we change first the lower bound of the variable an infeasibilty should be detected */
5352  assert(!infeasible);
5353 
5354  if( tightened )
5355  {
5356  (*nchgbds)++;
5357 
5358  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5360  }
5361 
5362 
5363  SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v], TRUE, &infeasible, &tightened) );
5364 
5365  /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5366  * bound update can be infeasible
5367  */
5368  if( infeasible )
5369  {
5371  {
5372  INFERINFO inferinfo;
5373  SCIP_VAR* var;
5374  int begin;
5375  int end;
5376 
5377  var = vars[v];
5378  assert(var != NULL);
5379 
5380  /* initialize conflict analysis */
5382 
5383  /* convert int to inference information */
5384  inferinfo = intToInferInfo(ubinferinfos[v]);
5385 
5386  /* collect time window from inference information */
5387  begin = inferInfoGetData1(inferinfo);
5388  end = inferInfoGetData2(inferinfo);
5389  assert(begin < end);
5390 
5391  /* added to lower bound (which was undercut be new upper bound) of the variable */
5392  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
5393 
5394  /* analysis the upper bound change */
5395  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5396  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5397  conshdlrdata->usebdwidening, explanation) );
5398 
5399  (*initialized) = TRUE;
5400  }
5401 
5402  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5403  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5404 
5405  (*cutoff) = TRUE;
5406  break;
5407  }
5408 
5409  if( tightened )
5410  {
5411  (*nchgbds)++;
5412 
5413  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5415  }
5416  }
5417 
5418  SCIPfreeBufferArray(scip, &ubinferinfos);
5419  SCIPfreeBufferArray(scip, &lbinferinfos);
5420  SCIPfreeBufferArray(scip, &newubs);
5421  SCIPfreeBufferArray(scip, &newlbs);
5422 
5423  /* free buffer arrays */
5424  SCIPfreeBufferArray(scip, &lsts);
5425  SCIPfreeBufferArray(scip, &ects);
5426  SCIPfreeBufferArray(scip, &ests);
5427  SCIPfreeBufferArray(scip, &lcts);
5428  SCIPfreeBufferArray(scip, &permests);
5429  SCIPfreeBufferArray(scip, &permlcts);
5430  SCIPfreeBufferArray(scip, &flexenergies);
5431  SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5432  SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5433 
5434  return SCIP_OKAY;
5435 }
5436 
5437 /** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5438  * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5439  * time table propagator
5440  */
5441 static
5443  SCIP* scip, /**< SCIP data structure */
5444  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5445  SCIP_PROFILE* profile, /**< core profile */
5446  int nvars, /**< number of start time variables (activities) */
5447  SCIP_VAR** vars, /**< array of start time variables */
5448  int* durations, /**< array of durations */
5449  int* demands, /**< array of demands */
5450  int capacity, /**< cumulative capacity */
5451  int hmin, /**< left bound of time axis to be considered (including hmin) */
5452  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5453  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5454  int* nchgbds, /**< pointer to store the number of bound changes */
5455  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5456  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5457  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5458  )
5459 {
5460  SCIP_Bool infeasible;
5461  int v;
5462 
5463  assert(scip != NULL);
5464  assert(nvars > 0);
5465  assert(cons != NULL);
5466  assert(cutoff != NULL);
5467 
5468  /* check if already a cutoff was detected */
5469  if( (*cutoff) )
5470  return SCIP_OKAY;
5471 
5472  /* check if the time tabling should infer bounds */
5473  if( !conshdlrdata->ttinfer )
5474  return SCIP_OKAY;
5475 
5476  assert(*initialized == FALSE);
5477 
5478  SCIPdebugMessage("propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5479  SCIPconsGetName(cons), hmin, hmax, capacity);
5480 
5481  infeasible = FALSE;
5482 
5483  /* if core profile is empty; nothing to do */
5484  if( SCIPprofileGetNTimepoints(profile) <= 1 )
5485  return SCIP_OKAY;
5486 
5487  /* start checking each job whether the bounds can be improved */
5488  for( v = 0; v < nvars; ++v )
5489  {
5490  SCIP_VAR* var;
5491  int demand;
5492  int duration;
5493  int begin;
5494  int end;
5495  int est;
5496  int lst;
5497 
5498  var = vars[v];
5499  assert(var != NULL);
5500 
5501  duration = durations[v];
5502  assert(duration > 0);
5503 
5504  /* collect earliest and latest start time */
5505  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5506  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5507 
5508  /* check if the start time variables is already fixed; in that case we can ignore the job */
5509  if( est == lst )
5510  continue;
5511 
5512  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5513  if( lst + duration <= hmin || est >= hmax )
5514  continue;
5515 
5516  /* compute core interval w.r.t. effective time horizon */
5517  begin = MAX(hmin, lst);
5518  end = MIN(hmax, est + duration);
5519 
5520  demand = demands[v];
5521  assert(demand > 0);
5522 
5523  /* if the job has a core, remove it first */
5524  if( begin < end )
5525  {
5526  SCIPdebugMessage("variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5527  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5528 
5529  SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5530  }
5531 
5532  /* first try to update the earliest start time */
5533  SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5534  profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5535 
5536  if( *cutoff )
5537  break;
5538 
5539  /* second try to update the latest start time */
5540  SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5541  profile, v, nchgbds) );
5542 
5543  if( *cutoff )
5544  break;
5545 
5546  /* collect the potentially updated earliest and latest start time */
5547  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5548  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5549 
5550  /* compute core interval w.r.t. effective time horizon */
5551  begin = MAX(hmin, lst);
5552  end = MIN(hmax, est + duration);
5553 
5554  /* after updating the bound we might have a new core */
5555  if( begin < end )
5556  {
5557  int pos;
5558 
5559  SCIPdebugMessage("variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5560  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5561 
5562  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5563 
5564  if( infeasible )
5565  {
5566  /* use conflict analysis to analysis the core insertion which was infeasible */
5567  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5568  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5569 
5570  if( explanation != NULL )
5571  explanation[v] = TRUE;
5572 
5573  (*cutoff) = TRUE;
5574 
5575  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5576  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
5577 
5578  break;
5579  }
5580  }
5581  }
5582 
5583  return SCIP_OKAY;
5584 }
5585 
5586 
5587 /** node data structure for the binary tree used for edgefinding (with overload checking) */
5588 struct SCIP_NodeData
5589 {
5590  SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5591  SCIP_Real key; /**< key which is to insert the corresponding search node */
5592  int est; /**< earliest start time if the node data belongs to a leaf */
5593  int lct; /**< latest completion time if the node data belongs to a leaf */
5594  int demand; /**< demand of the job if the node data belongs to a leaf */
5595  int duration; /**< duration of the job if the node data belongs to a leaf */
5596  int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5597  int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5598  int enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5599  int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5600  int energylambda;
5601  int enveloplambda;
5602  int idx; /**< index of the start time variable in the (global) variable array */
5603  SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5604 };
5605 typedef struct SCIP_NodeData SCIP_NODEDATA;
5607 /** creates a node data structure */
5608 static
5610  SCIP* scip, /**< SCIP data structure */
5611  SCIP_NODEDATA** nodedata /**< pointer to store the create node data */
5612  )
5613 {
5614  SCIP_CALL( SCIPallocBuffer(scip, nodedata) );
5615  (*nodedata)->var = NULL;
5616  (*nodedata)->key = SCIP_INVALID;
5617  (*nodedata)->est = INT_MIN;
5618  (*nodedata)->lct = INT_MAX;
5619  (*nodedata)->duration = 0;
5620  (*nodedata)->demand = 0;
5621  (*nodedata)->enveloptheta = -1;
5622  (*nodedata)->energytheta = 0;
5623  (*nodedata)->enveloplambda = -1;
5624  (*nodedata)->energylambda = -1;
5625  (*nodedata)->idx = -1;
5626  (*nodedata)->intheta = TRUE;
5627 
5628  return SCIP_OKAY;
5629 }
5630 
5631 /** frees a node data structure */
5632 static
5633 void freeNodedata(
5634  SCIP* scip, /**< SCIP data structure */
5635  SCIP_NODEDATA** nodedata /**< pointer to store node data which should be freed */
5636  )
5637 {
5638  if( *nodedata != NULL )
5639  {
5640  SCIPfreeBuffer(scip, nodedata);
5641  }
5642 }
5643 
5644 /** update node data structure strating form the given node along the path to the root node */
5645 static
5647  SCIP* scip, /**< SCIP data structure */
5648  SCIP_BTNODE* node /**< search node which inserted */
5649  )
5650 {
5651  SCIP_BTNODE* left;
5652  SCIP_BTNODE* right;
5653  SCIP_NODEDATA* nodedata;
5654  SCIP_NODEDATA* leftdata;
5655  SCIP_NODEDATA* rightdata;
5656 
5657  SCIPdebugMessage("update envelop starting from node <%p>\n", (void*)node);
5658 
5659  if( SCIPbtnodeIsLeaf(node) )
5660  node = SCIPbtnodeGetParent(node);
5661 
5662  while( node != NULL )
5663  {
5664  /* get node data */
5665  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5666  assert(nodedata != NULL);
5667 
5668  /* collect node data from left node */
5669  left = SCIPbtnodeGetLeftchild(node);
5670  assert(left != NULL);
5671  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5672  assert(leftdata != NULL);
5673 
5674  /* collect node data from right node */
5675  right = SCIPbtnodeGetRightchild(node);
5676  assert(right != NULL);
5677  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5678  assert(rightdata != NULL);
5679 
5680  /* update envelop and energy */
5681  if( leftdata->enveloptheta >= 0 )
5682  {
5683  assert(rightdata->energytheta != -1);
5684  nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5685  }
5686  else
5687  nodedata->enveloptheta = rightdata->enveloptheta;
5688 
5689  assert(leftdata->energytheta != -1);
5690  assert(rightdata->energytheta != -1);
5691  nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5692 
5693  if( leftdata->enveloplambda >= 0 )
5694  {
5695  assert(rightdata->energytheta != -1);
5696  nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5697  }
5698  else
5699  nodedata->enveloplambda = rightdata->enveloplambda;
5700 
5701  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5702  nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5703 
5704  SCIPdebugMessage("node <%p> lambda envelop %d\n", (void*)node, nodedata->enveloplambda);
5705 
5706  if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5707  {
5708  assert(rightdata->energytheta != -1);
5709  assert(leftdata->energytheta != -1);
5710  nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5711  }
5712  else if( rightdata->energylambda >= 0 )
5713  {
5714  assert(leftdata->energytheta != -1);
5715  nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5716  }
5717  else if( leftdata->energylambda >= 0 )
5718  {
5719  assert(rightdata->energytheta != -1);
5720  nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5721  }
5722  else
5723  nodedata->energylambda = -1;
5724 
5725  /* go to parent */
5726  node = SCIPbtnodeGetParent(node);
5727  }
5728 
5729  SCIPdebugMessage("updating done\n");
5730 
5731  return SCIP_OKAY;
5732 }
5733 
5734 /** updates the key of the first parent on the trace which comes from left */
5735 static
5736 void updateKeyOnTrace(
5737  SCIP_BTNODE* node, /**< node to start the trace */
5738  SCIP_Real key /**< update search key */
5739  )
5740 {
5741  assert(node != NULL);
5742 
5743  while( !SCIPbtnodeIsRoot(node) )
5744  {
5745  SCIP_BTNODE* parent;
5746 
5747  parent = SCIPbtnodeGetParent(node);
5748  assert(parent != NULL);
5749 
5750  if( SCIPbtnodeIsLeftchild(node) )
5751  {
5752  SCIP_NODEDATA* nodedata;
5753 
5754  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(parent);
5755  assert(nodedata != NULL);
5756 
5757  nodedata->key = key;
5758  return;
5759  }
5760 
5761  node = parent;
5762  }
5763 }
5764 
5765 
5766 /** deletes the given node and updates all envelops */
5767 static
5769  SCIP* scip, /**< SCIP data structure */
5770  SCIP_BT* tree, /**< binary tree */
5771  SCIP_BTNODE* node /**< node to be deleted */
5772  )
5773 {
5774  SCIP_BTNODE* parent;
5775  SCIP_BTNODE* grandparent;
5776  SCIP_BTNODE* sibling;
5777 
5778  assert(scip != NULL);
5779  assert(tree != NULL);
5780  assert(node != NULL);
5781 
5782  assert(SCIPbtnodeIsLeaf(node));
5783  assert(!SCIPbtnodeIsRoot(node));
5784 
5785  SCIPdebugMessage("delete node <%p>\n", (void*)node);
5786 
5787  parent = SCIPbtnodeGetParent(node);
5788  assert(parent != NULL);
5789  if( SCIPbtnodeIsLeftchild(node) )
5790  {
5791  sibling = SCIPbtnodeGetRightchild(parent);
5792  SCIPbtnodeSetRightchild(parent, NULL);
5793  }
5794  else
5795  {
5796  sibling = SCIPbtnodeGetLeftchild(parent);
5797  SCIPbtnodeSetLeftchild(parent, NULL);
5798  }
5799  assert(sibling != NULL);
5800 
5801  grandparent = SCIPbtnodeGetParent(parent);
5802 
5803  if( grandparent != NULL )
5804  {
5805  /* reset parent of sibling */
5806  SCIPbtnodeSetParent(sibling, grandparent);
5807 
5808  /* reset child of grandparent to sibling */
5809  if( SCIPbtnodeIsLeftchild(parent) )
5810  {
5811  SCIPbtnodeSetLeftchild(grandparent, sibling);
5812  }
5813  else
5814  {
5815  SCIP_NODEDATA* nodedata;
5816 
5817  assert(SCIPbtnodeIsRightchild(parent));
5818  SCIPbtnodeSetRightchild(grandparent, sibling);
5819 
5820  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(sibling);
5821 
5822  updateKeyOnTrace(grandparent, nodedata->key);
5823  }
5824 
5825  SCIP_CALL( updateEnvelop(scip, grandparent) );
5826  }
5827  else
5828  {
5829  SCIPbtnodeSetParent(sibling, NULL);
5830 
5831  SCIPbtSetRoot(tree, sibling);
5832  }
5833 
5834 
5835  SCIPbtnodeFree(tree, &parent);
5836 
5837  return SCIP_OKAY;
5838 }
5839 
5840 /** moves a node form the theta set into the lambda set and updates the envelops */
5841 static
5843  SCIP* scip, /**< SCIP data structure */
5844  SCIP_BT* tree, /**< binary tree */
5845  SCIP_BTNODE* node /**< node to move into the lambda set */
5846  )
5847 {
5848  SCIP_NODEDATA* nodedata;
5849 
5850  assert(scip != NULL);
5851  assert(tree != NULL);
5852  assert(node != NULL);
5853 
5854  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5855  assert(nodedata != NULL);
5856  assert(nodedata->intheta);
5857 
5858  /* move the contributions form the theta set into the lambda set */
5859  assert(nodedata->enveloptheta != -1);
5860  assert(nodedata->energytheta != -1);
5861  assert(nodedata->enveloplambda == -1);
5862  assert(nodedata->energylambda == -1);
5863  nodedata->enveloplambda = nodedata->enveloptheta;
5864  nodedata->energylambda = nodedata->energytheta;
5865 
5866  nodedata->enveloptheta = -1;
5867  nodedata->energytheta = 0;
5868  nodedata->intheta = FALSE;
5869 
5870  /* update the energy and envelop values on trace */
5871  SCIP_CALL( updateEnvelop(scip, node) );
5872 
5873  return SCIP_OKAY;
5874 }
5875 
5876 /** inserts a node into the theta set and update the envelops */
5877 static
5879  SCIP* scip, /**< SCIP data structure */
5880  SCIP_BT* tree, /**< binary tree */
5881  SCIP_BTNODE* node, /**< node to insert */
5882  SCIP_NODEDATA** nodedatas, /**< array of node data */
5883  int* nnodedatas /**< pointer to number of node data */
5884  )
5885 {
5886  /* if the tree is empty the node will be the root node */
5887  if( SCIPbtIsEmpty(tree) )
5888  {
5889  SCIPbtSetRoot(tree, node);
5890  }
5891  else
5892  {
5893  SCIP_NODEDATA* newnodedata;
5894  SCIP_NODEDATA* leafdata;
5895  SCIP_NODEDATA* nodedata;
5896  SCIP_BTNODE* leaf;
5897  SCIP_BTNODE* newnode;
5898  SCIP_BTNODE* parent;
5899 
5900  leaf = SCIPbtGetRoot(tree);
5901  assert(leaf != NULL);
5902 
5903  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5904  assert(leafdata != NULL);
5905 
5906  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5907  assert(nodedata != NULL);
5908  assert(nodedata->intheta);
5909 
5910  /* find the position to insert the node */
5911  while( !SCIPbtnodeIsLeaf(leaf) )
5912  {
5913  if( nodedata->key < leafdata->key )
5914  leaf = SCIPbtnodeGetLeftchild(leaf);
5915  else
5916  leaf = SCIPbtnodeGetRightchild(leaf);
5917 
5918  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5919  assert(leafdata != NULL);
5920  }
5921 
5922  assert(leaf != NULL);
5923  assert(leaf != node);
5924 
5925  /* create node data */
5926  SCIP_CALL( createNodedata(scip, &newnodedata) );
5927 
5928  /* create a new node */
5929  SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
5930  assert(newnode != NULL);
5931 
5932  /* store node data to be able to delete them latter */
5933  nodedatas[*nnodedatas] = newnodedata;
5934  (*nnodedatas)++;
5935 
5936  parent = SCIPbtnodeGetParent(leaf);
5937 
5938  if( parent != NULL )
5939  {
5940  SCIPbtnodeSetParent(newnode, parent);
5941 
5942  /* check if the node is the left child */
5943  if( SCIPbtnodeGetLeftchild(parent) == leaf )
5944  {
5945  SCIPbtnodeSetLeftchild(parent, newnode);
5946  }
5947  else
5948  {
5949  SCIPbtnodeSetRightchild(parent, newnode);
5950  }
5951  }
5952  else
5953  SCIPbtSetRoot(tree, newnode);
5954 
5955  if( nodedata->key < leafdata->key )
5956  {
5957  /* node is on the left */
5958  SCIPbtnodeSetLeftchild(newnode, node);
5959  SCIPbtnodeSetRightchild(newnode, leaf);
5960  newnodedata->key = nodedata->key;
5961  }
5962  else
5963  {
5964  /* leaf is on the left */
5965  SCIPbtnodeSetLeftchild(newnode, leaf);
5966  SCIPbtnodeSetRightchild(newnode, node);
5967  newnodedata->key = leafdata->key;
5968  }
5969 
5970  SCIPbtnodeSetParent(leaf, newnode);
5971  SCIPbtnodeSetParent(node, newnode);
5972  }
5973 
5974  /* update envelop */
5975  SCIP_CALL( updateEnvelop(scip, node) );
5976 
5977  return SCIP_OKAY;
5978 }
5979 
5980 /** returns the leaf responsible for the lambda energy */
5981 static
5983  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
5984  )
5985 {
5986  SCIP_BTNODE* left;
5987  SCIP_BTNODE* right;
5988  SCIP_NODEDATA* nodedata;
5989  SCIP_NODEDATA* leftdata;
5990  SCIP_NODEDATA* rightdata;
5991 
5992  assert(node != NULL);
5993 
5994  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5995  assert(nodedata != NULL);
5996 
5997  /* check if the node is the (responsible) leaf */
5998  if( SCIPbtnodeIsLeaf(node) )
5999  {
6000  assert(!nodedata->intheta);
6001  return node;
6002  }
6003 
6004  left = SCIPbtnodeGetLeftchild(node);
6005  assert(left != NULL);
6006 
6007  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6008  assert(leftdata != NULL);
6009 
6010  right = SCIPbtnodeGetRightchild(node);
6011  assert(right != NULL);
6012 
6013  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6014  assert(rightdata != NULL);
6015 
6016  assert(nodedata->energylambda != -1);
6017  assert(rightdata->energytheta != -1);
6018 
6019  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6021 
6022  assert(leftdata->energytheta != -1);
6023  assert(rightdata->energylambda != -1);
6024  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6025 
6027 }
6028 
6029 /** returns the leaf responsible for the lambda envelop */
6030 static
6032  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6033  )
6034 {
6035  SCIP_BTNODE* left;
6036  SCIP_BTNODE* right;
6037  SCIP_NODEDATA* nodedata;
6038  SCIP_NODEDATA* leftdata;
6039  SCIP_NODEDATA* rightdata;
6040 
6041  assert(node != NULL);
6042 
6043  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6044  assert(nodedata != NULL);
6045 
6046  /* check if the node is the (responsible) leaf */
6047  if( SCIPbtnodeIsLeaf(node) )
6048  {
6049  assert(!nodedata->intheta);
6050  return node;
6051  }
6052 
6053  left = SCIPbtnodeGetLeftchild(node);
6054  assert(left != NULL);
6055 
6056  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6057  assert(leftdata != NULL);
6058 
6059  right = SCIPbtnodeGetRightchild(node);
6060  assert(right != NULL);
6061 
6062  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6063  assert(rightdata != NULL);
6064 
6065  assert(nodedata->enveloplambda != -1);
6066  assert(rightdata->energytheta != -1);
6067 
6068  /* check if the left or right child is the one defining the envelop for the lambda set */
6069  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6071  else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6072  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6074 
6075  assert(rightdata->enveloplambda != -1);
6076  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6077 
6079 }
6080 
6081 
6082 /** reports all elements from set theta to generate a conflicting set */
6083 static
6084 void collectThetaSubtree(
6085  SCIP_BTNODE* node, /**< node within a theta subtree */
6086  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6087  int* nelements, /**< pointer to store the number of elements in omegaset */
6088  int* est, /**< pointer to store the earliest start time of the omega set */
6089  int* lct, /**< pointer to store the latest start time of the omega set */
6090  int* energy /**< pointer to store the energy of the omega set */
6091  )
6092 {
6093  SCIP_NODEDATA* nodedata;
6094 
6095  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6096  assert(nodedata != NULL);
6097 
6098  if( !SCIPbtnodeIsLeaf(node) )
6099  {
6100  collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6101  collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6102  }
6103  else if( nodedata->intheta )
6104  {
6105  assert(nodedata->var != NULL);
6106  SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6107 
6108  omegaset[*nelements] = node;
6109  (*est) = MIN(*est, nodedata->est);
6110  (*lct) = MAX(*lct, nodedata->lct);
6111  (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6112  (*nelements)++;
6113  }
6114 }
6115 
6116 
6117 /** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6118 static
6119 void traceThetaEnvelop(
6120  SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6121  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6122  int* nelements, /**< pointer to store the number of elements in omegaset */
6123  int* est, /**< pointer to store the earliest start time of the omega set */
6124  int* lct, /**< pointer to store the latest start time of the omega set */
6125  int* energy /**< pointer to store the energy of the omega set */
6126  )
6127 {
6128  assert(node != NULL);
6129 
6130  if( SCIPbtnodeIsLeaf(node) )
6131  {
6132  collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6133  }
6134  else
6135  {
6136  SCIP_BTNODE* left;
6137  SCIP_BTNODE* right;
6138  SCIP_NODEDATA* nodedata;
6139  SCIP_NODEDATA* leftdata;
6140  SCIP_NODEDATA* rightdata;
6141 
6142  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6143  assert(nodedata != NULL);
6144 
6145 
6146  left = SCIPbtnodeGetLeftchild(node);
6147  assert(left != NULL);
6148 
6149  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6150  assert(leftdata != NULL);
6151 
6152  right = SCIPbtnodeGetRightchild(node);
6153  assert(right != NULL);
6154 
6155  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6156  assert(rightdata != NULL);
6157 
6158  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6159  assert(nodedata != NULL);
6160 
6161  assert(nodedata->enveloptheta != -1);
6162  assert(rightdata->energytheta != -1);
6163 
6164  if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6165  {
6166  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6167  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6168  }
6169  else
6170  {
6171  assert(rightdata->enveloptheta != -1);
6172  assert(nodedata->enveloptheta == rightdata->enveloptheta);
6173  traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6174  }
6175  }
6176 }
6177 
6178 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6179 static
6180 void traceLambdaEnergy(
6181  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6182  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6183  int* nelements, /**< pointer to store the number of elements in omega set */
6184  int* est, /**< pointer to store the earliest start time of the omega set */
6185  int* lct, /**< pointer to store the latest start time of the omega set */
6186  int* energy /**< pointer to store the energy of the omega set */
6187  )
6188 {
6189  SCIP_BTNODE* left;
6190  SCIP_BTNODE* right;
6191  SCIP_NODEDATA* nodedata;
6192  SCIP_NODEDATA* leftdata;
6193  SCIP_NODEDATA* rightdata;
6194 
6195  assert(node != NULL);
6196 
6197  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6198  assert(nodedata != NULL);
6199 
6200  /* check if the node is a leaf */
6201  if( SCIPbtnodeIsLeaf(node) )
6202  return;
6203 
6204  left = SCIPbtnodeGetLeftchild(node);
6205  assert(left != NULL);
6206 
6207  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6208  assert(leftdata != NULL);
6209 
6210  right = SCIPbtnodeGetRightchild(node);
6211  assert(right != NULL);
6212 
6213  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6214  assert(rightdata != NULL);
6215 
6216  assert(nodedata->energylambda != -1);
6217  assert(rightdata->energytheta != -1);
6218 
6219  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6220  {
6221  traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6222  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6223  }
6224  else
6225  {
6226  assert(leftdata->energytheta != -1);
6227  assert(rightdata->energylambda != -1);
6228  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6229 
6230  collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6231  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6232  }
6233 }
6234 
6235 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6236 static
6237 void traceLambdaEnvelop(
6238  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6239  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6240  int* nelements, /**< pointer to store the number of elements in omega set */
6241  int* est, /**< pointer to store the earliest start time of the omega set */
6242  int* lct, /**< pointer to store the latest start time of the omega set */
6243  int* energy /**< pointer to store the energy of the omega set */
6244  )
6245 {
6246  SCIP_BTNODE* left;
6247  SCIP_BTNODE* right;
6248  SCIP_NODEDATA* nodedata;
6249  SCIP_NODEDATA* leftdata;
6250  SCIP_NODEDATA* rightdata;
6251 
6252  assert(node != NULL);
6253 
6254  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6255  assert(nodedata != NULL);
6256 
6257  /* check if the node is a leaf */
6258  if( SCIPbtnodeIsLeaf(node) )
6259  {
6260  assert(!nodedata->intheta);
6261  return;
6262  }
6263 
6264  left = SCIPbtnodeGetLeftchild(node);
6265  assert(left != NULL);
6266 
6267  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6268  assert(leftdata != NULL);
6269 
6270  right = SCIPbtnodeGetRightchild(node);
6271  assert(right != NULL);
6272 
6273  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6274  assert(rightdata != NULL);
6275 
6276  assert(nodedata->enveloplambda != -1);
6277  assert(rightdata->energytheta != -1);
6278 
6279  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6280  {
6281  traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6282  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6283  }
6284  else
6285  {
6286  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6287  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6288  {
6289  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6290  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6291  }
6292  else
6293  {
6294  assert(rightdata->enveloplambda != -1);
6295  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6296  traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6297  }
6298  }
6299 }
6300 
6301 /** compute the energy contribution by job which corresponds to the given leaf */
6302 static
6304  SCIP_BTNODE* node /**< leaf */
6305  )
6306 {
6307  SCIP_NODEDATA* nodedata;
6308  int duration;
6309 
6310  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6311  assert(nodedata != NULL);
6312  assert(nodedata->var != NULL);
6313 
6314  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6315  assert(duration > 0);
6316 
6317  SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6318  SCIPvarGetName(nodedata->var), SCIPvarGetLbLocal(nodedata->var), SCIPvarGetUbLocal(nodedata->var),
6319  SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6320 
6321  /* return energy which is contributed by the start time variable */
6322  return nodedata->demand * duration;
6323 }
6324 
6325 /** comparison method for two node data w.r.t. the earliest start time */
6326 static
6327 SCIP_DECL_SORTPTRCOMP(compNodeEst)
6329  int est1;
6330  int est2;
6331 
6332  est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6333  est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6334 
6335  return (est1 - est2);
6336 }
6337 
6338 /** comparison method for two node data w.r.t. the latest completion time */
6339 static
6340 SCIP_DECL_SORTPTRCOMP(compNodedataLct)
6342  int lct1;
6343  int lct2;
6344 
6345  lct1 = ((SCIP_NODEDATA*)elem1)->lct;
6346  lct2 = ((SCIP_NODEDATA*)elem2)->lct;
6347 
6348  return (lct1 - lct2);
6349 }
6350 
6351 
6352 /** an overload was detected; initialized conflict analysis, add an initial reason
6353  *
6354  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6355  */
6356 static
6358  SCIP* scip, /**< SCIP data structure */
6359  SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6360  int capacity, /**< cumulative capacity */
6361  int nleaves, /**< number of responsible leaves */
6362  int est, /**< earliest start time of the ...... */
6363  int lct, /**< latest completly time of the .... */
6364  int reportedenergy, /**< energy which already reported */
6365  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6366  int shift, /**< shift applied to all jobs before adding them to the tree */
6367  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6368  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6369  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6370  )
6371 {
6372  int energy;
6373  int j;
6374 
6375  /* do nothing if conflict analysis is not applicable */
6377  return SCIP_OKAY;
6378 
6379  SCIPdebugMessage("est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6380 
6381  /* compute energy of initial time window */
6382  energy = (lct - est) * capacity;
6383 
6384  /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6385  SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6386 
6387  /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6388  * thereby, compute the time window of interest
6389  */
6390  for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6391  {
6392  SCIP_NODEDATA* nodedata;
6393 
6394  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6395  assert(nodedata != NULL);
6396 
6397  reportedenergy += computeEnergyContribution(leaves[j]);
6398 
6399  /* adjust energy if the earliest start time decrease */
6400  if( nodedata->est < est )
6401  {
6402  est = nodedata->est;
6403  energy = (lct - est) * capacity;
6404  }
6405  }
6406  assert(reportedenergy > energy);
6407 
6408  SCIPdebugMessage("time window [%d,%d) available energy %d, required energy %d\n", est, lct, energy, reportedenergy);
6409 
6410  /* initialize conflict analysis */
6412 
6413  /* flip earliest start time and latest completion time */
6414  if( !propest )
6415  {
6416  SCIPswapInts(&est, &lct);
6417 
6418  /* shift earliest start time and latest completion time */
6419  lct = shift - lct;
6420  est = shift - est;
6421  }
6422  else
6423  {
6424  /* shift earliest start time and latest completion time */
6425  lct = lct + shift;
6426  est = est + shift;
6427  }
6428 
6429  nleaves = j;
6430 
6431  /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6432  * overloaded
6433  */
6434  for( j = nleaves-1; j >= 0; --j )
6435  {
6436  SCIP_NODEDATA* nodedata;
6437 
6438  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6439  assert(nodedata != NULL);
6440  assert(nodedata->var != NULL);
6441 
6442  /* check if bound widening should be used */
6443  if( usebdwidening )
6444  {
6445  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6446  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6447  }
6448  else
6449  {
6450  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6451  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6452  }
6453 
6454  if( explanation != NULL )
6455  explanation[nodedata->idx] = TRUE;
6456  }
6457 
6458  (*initialized) = TRUE;
6459 
6460  return SCIP_OKAY;
6461 }
6462 
6463 /** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6464  * responsible interval bounds in *est_omega and *lct_omega
6465  */
6466 static
6467 int computeEstOmegaset(
6468  SCIP* scip, /**< SCIP data structure */
6469  int duration, /**< duration of the job to move */
6470  int demand, /**< demand of the job to move */
6471  int capacity, /**< cumulative capacity */
6472  int est, /**< earliest start time of the omega set */
6473  int lct, /**< latest start time of the omega set */
6474  int energy /**< energy of the omega set */
6475  )
6476 {
6477  int newest;
6478 
6479  newest = 0;
6480 
6481  assert(scip != NULL);
6482 
6483  if( energy > (capacity - demand) * (lct - est) )
6484  {
6485  if( energy + demand * duration > capacity * (lct - est) )
6486  {
6487  newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6488  newest += est;
6489  }
6490  }
6491 
6492  return newest;
6493 }
6494 
6495 /** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6496  *
6497  * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6498  * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802–816, 2009.
6499  */
6500 static
6502  SCIP* scip, /**< SCIP data structure */
6503  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6504  SCIP_CONS* cons, /**< constraint which is propagated */
6505  SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6506  SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6507  int capacity, /**< cumulative capacity */
6508  int ncands, /**< number of candidates */
6509  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6510  int shift, /**< shift applied to all jobs before adding them to the tree */
6511  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6512  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6513  int* nchgbds, /**< pointer to store the number of bound changes */
6514  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6515  )
6516 {
6517  SCIP_NODEDATA* rootdata;
6518  int j;
6519 
6520  assert(!SCIPbtIsEmpty(tree));
6521 
6522  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6523  assert(rootdata != NULL);
6524 
6525  /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6526  for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6527  {
6528  SCIP_NODEDATA* nodedata;
6529 
6530  if( SCIPbtnodeIsRoot(leaves[j]) )
6531  break;
6532 
6533  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6534  assert(nodedata->est != -1);
6535 
6536  /* check if the root lambda envelop exeeds the available capacity */
6537  while( !(*cutoff) && rootdata->enveloplambda > capacity * nodedata->lct )
6538  {
6539  SCIP_BTNODE** omegaset;
6540  SCIP_BTNODE* leaf;
6541  SCIP_NODEDATA* leafdata;
6542  int nelements;
6543  int energy;
6544  int newest;
6545  int est;
6546  int lct;
6547 
6548  assert(!(*cutoff));
6549 
6550  /* find responsible leaf for the lambda envelope */
6552  assert(leaf != NULL);
6553  assert(SCIPbtnodeIsLeaf(leaf));
6554 
6555  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6556  assert(leafdata != NULL);
6557  assert(!leafdata->intheta);
6558  assert(leafdata->duration > 0);
6559  assert(leafdata->est >= 0);
6560 
6561  /* check if the job has to be removed since its latest completion is to large */
6562  if( leafdata->est + leafdata->duration >= nodedata->lct )
6563  {
6564  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6565 
6566  /* the root might changed therefore we need to collect the new root node data */
6567  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6568  assert(rootdata != NULL);
6569 
6570  continue;
6571  }
6572 
6573  /* compute omega set */
6574  SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6575 
6576  nelements = 0;
6577  est = INT_MAX;
6578  lct = INT_MIN;
6579  energy = 0;
6580 
6581  /* collect the omega set from theta set */
6582  traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6583  assert(nelements > 0);
6584  assert(nelements < ncands);
6585 
6586  newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6587 
6588  /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6589  if( newest > lct )
6590  {
6591  SCIPdebugMessage("an overload was detected duration edge-finder propagattion\n");
6592 
6593  /* analyze over load */
6594  SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6595  conshdlrdata->usebdwidening, initialized, explanation) );
6596  (*cutoff) = TRUE;
6597 
6598  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6599  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6600  }
6601  else if( newest > 0 )
6602  {
6603  SCIP_Bool infeasible;
6604  SCIP_Bool tightened;
6605  INFERINFO inferinfo;
6606 
6607  if( propest )
6608  {
6609  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6610  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6611 
6612  SCIPdebugMessage("variable <%s> adjust lower bound from %g to %d\n",
6613  SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6614 
6615  SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6616  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6617 
6618  /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6620  }
6621  else
6622  {
6623  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6624  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6625 
6626  SCIPdebugMessage("variable <%s> adjust upper bound from %g to %d\n",
6627  SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6628 
6629  SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6630  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6631 
6632  /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6634  }
6635 
6636  /* adjust the earliest start time */
6637  if( tightened )
6638  {
6639  leafdata->est = newest;
6640  (*nchgbds)++;
6641  }
6642 
6643  if( infeasible )
6644  {
6645  /* initialize conflict analysis if conflict analysis is applicable */
6647  {
6648  int i;
6649 
6650  SCIPdebugMessage("edge-finder dectected an infeasibility\n");
6651 
6653 
6654  /* add lower and upper bound of variable which leads to the infeasibilty */
6655  SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6656  SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6657 
6658  if( explanation != NULL )
6659  explanation[leafdata->idx] = TRUE;
6660 
6661  /* add lower and upper bound of variable which lead to the infeasibilty */
6662  for( i = 0; i < nelements; ++i )
6663  {
6664  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6665  assert(nodedata != NULL);
6666 
6667  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6668  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6669 
6670  if( explanation != NULL )
6671  explanation[nodedata->idx] = TRUE;
6672  }
6673 
6674  (*initialized) = TRUE;
6675  }
6676 
6677  (*cutoff) = TRUE;
6678 
6679  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6680  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6681  }
6682  }
6683 
6684  /* free omegaset array */
6685  SCIPfreeBufferArray(scip, &omegaset);
6686 
6687  /* delete responsible leaf from lambda */
6688  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6689 
6690  /* the root might changed therefore we need to collect the new root node data */
6691  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6692  assert(rootdata != NULL);
6693  }
6694 
6695  /* move current job j from the theta set into the lambda set */
6696  SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6697  }
6698 
6699  return SCIP_OKAY;
6700 }
6701 
6702 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6703  *
6704  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6705  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6706  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6707  */
6708 static
6710  SCIP* scip, /**< SCIP data structure */
6711  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6712  int nvars, /**< number of start time variables (activities) */
6713  SCIP_VAR** vars, /**< array of start time variables */
6714  int* durations, /**< array of durations */
6715  int* demands, /**< array of demands */
6716  int capacity, /**< cumulative capacity */
6717  int hmin, /**< left bound of time axis to be considered (including hmin) */
6718  int hmax, /**< right bound of time axis to be considered (not including hmax) */
6719  SCIP_CONS* cons, /**< constraint which is propagated */
6720  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6721  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6722  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6723  int* nchgbds, /**< pointer to store the number of bound changes */
6724  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6725  )
6726 {
6727  SCIP_NODEDATA** nodedatas;
6728  SCIP_BTNODE** leaves;
6729  SCIP_BT* tree;
6730 
6731  int totalenergy;
6732  int nnodedatas;
6733  int ninsertcands;
6734  int ncands;
6735 
6736  int shift;
6737  int j;
6738 
6739  assert(scip != NULL);
6740  assert(cons != NULL);
6741  assert(initialized != NULL);
6742  assert(cutoff != NULL);
6743  assert(*cutoff == FALSE);
6744 
6745  SCIPdebugMessage("check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6746 
6747  SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6748  SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6749 
6750  ncands = 0;
6751  totalenergy = 0;
6752 
6753  SCIP_CALL( SCIPbtCreate(&tree, SCIPblkmem(scip)) );
6754 
6755  /* compute the shift which we apply to compute .... latest completion time of all jobs */
6756  if( propest )
6757  shift = 0;
6758  else
6759  {
6760  shift = 0;
6761 
6762  /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6763  * earliest start time propagation to handle the latest completion times
6764  */
6765  for( j = 0; j < nvars; ++j )
6766  {
6767  int lct;
6768 
6769  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6770  shift = MAX(shift, lct);
6771  }
6772  }
6773 
6774  /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6775  * horizon
6776  */
6777  for( j = 0; j < nvars; ++j )
6778  {
6779  SCIP_NODEDATA* nodedata;
6780  SCIP_VAR* var;
6781  int duration;
6782  int leftadjust;
6783  int rightadjust;
6784  int energy;
6785  int est;
6786  int lct;
6787 
6788  var = vars[j];
6789  assert(var != NULL);
6790 
6791  duration = durations[j];
6792  assert(duration > 0);
6793 
6794  leftadjust = 0;
6795  rightadjust = 0;
6796 
6797  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
6798  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6799 
6800  /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6801  * effective horizon [hmin,hmax)
6802  */
6803  if( conshdlrdata->useadjustedjobs )
6804  {
6805  if( est < hmin )
6806  {
6807  leftadjust = (hmin - est);
6808  est = hmin;
6809  }
6810  if( lct > hmax )
6811  {
6812  rightadjust = (lct - hmax);
6813  lct = hmax;
6814  }
6815 
6816  /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6817  * with the effective time horizon
6818  */
6819  if( duration - leftadjust - rightadjust <= 0 )
6820  continue;
6821  }
6822  else if( est < hmin || lct > hmax )
6823  continue;
6824 
6825  energy = demands[j] * (duration - leftadjust - rightadjust);
6826  assert(energy > 0);
6827 
6828  totalenergy += energy;
6829 
6830  /* flip earliest start time and latest completion time */
6831  if( !propest )
6832  {
6833  SCIPswapInts(&est, &lct);
6834 
6835  /* shift earliest start time and latest completion time */
6836  lct = shift - lct;
6837  est = shift - est;
6838  }
6839  else
6840  {
6841  /* shift earliest start time and latest completion time */
6842  lct = lct - shift;
6843  est = est - shift;
6844  }
6845  assert(est < lct);
6846  assert(est >= 0);
6847  assert(lct >= 0);
6848 
6849  /* create search node data */
6850  SCIP_CALL( createNodedata(scip, &nodedata) );
6851 
6852  /* initialize search node data */
6853  /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6854  nodedata->key = est + j / (2.0 * nvars);
6855  nodedata->var = var;
6856  nodedata->est = est;
6857  nodedata->lct = lct;
6858  nodedata->demand = demands[j];
6859  nodedata->duration = duration;
6860  nodedata->leftadjust = leftadjust;
6861  nodedata->rightadjust = rightadjust;
6862 
6863  /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6864  * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6865  * particular time interval [a,b] against the time interval [0,b].
6866  */
6867  nodedata->enveloptheta = capacity * est + energy;
6868  nodedata->energytheta = energy;
6869  nodedata->enveloplambda = -1;
6870  nodedata->energylambda = -1;
6871 
6872  nodedata->idx = j;
6873  nodedata->intheta = TRUE;
6874 
6875  nodedatas[ncands] = nodedata;
6876  ncands++;
6877  }
6878 
6879  nnodedatas = ncands;
6880 
6881  /* sort (non-decreasing) the jobs w.r.t. latest completion times */
6882  SCIPsortPtr((void**)nodedatas, compNodedataLct, ncands);
6883 
6884  ninsertcands = 0;
6885 
6886  /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
6887  * the root envelop detects an overload
6888  */
6889  for( j = 0; j < ncands; ++j )
6890  {
6891  SCIP_BTNODE* leaf;
6892  SCIP_NODEDATA* rootdata;
6893 
6894  /* check if the new job opens a time window which size is so large that it offers more energy than the total
6895  * energy of all candidate jobs. If so we skip that one.
6896  */
6897  if( (nodedatas[j]->lct - nodedatas[j]->est) * capacity >= totalenergy )
6898  {
6899  /* set the earliest start time to minus one to mark that candidate to be not used */
6900  nodedatas[j]->est = -1;
6901  continue;
6902  }
6903 
6904  /* create search node */
6905  SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)nodedatas[j]) );
6906 
6907  /* insert new node into the theta set and updete the envelops */
6908  SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, &nnodedatas) );
6909  assert(nnodedatas <= 2*nvars);
6910 
6911  /* move the inserted candidates together */
6912  leaves[ninsertcands] = leaf;
6913  ninsertcands++;
6914 
6915  assert(!SCIPbtIsEmpty(tree));
6916  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6917  assert(rootdata != NULL);
6918 
6919  /* check if the theta set envelops exceeds the available capacity */
6920  if( rootdata->enveloptheta > capacity * nodedatas[j]->lct )
6921  {
6922  SCIPdebugMessage("detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[j]->lct, j);
6923  (*cutoff) = TRUE;
6924 
6925  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6926  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverload++ );
6927 
6928  break;
6929  }
6930  }
6931 
6932  /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
6933  if( *cutoff )
6934  {
6935  int glbenery;
6936  int est;
6937  int lct;
6938 
6939  glbenery = 0;
6940  est = nodedatas[j]->est;
6941  lct = nodedatas[j]->lct;
6942 
6943  /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
6944  * which led to an overload
6945  */
6946  for( j = j+1; j < ncands; ++j )
6947  {
6948  SCIP_NODEDATA* nodedata;
6949  int duration;
6950  int glbest;
6951  int glblct;
6952 
6953  nodedata = nodedatas[j];
6954  assert(nodedata != NULL);
6955 
6956  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6957 
6958  /* get latest start time */
6959  glbest = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(nodedata->var));
6960  glblct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
6961 
6962  /* check if parts of the jobs run with the time window defined by the last inserted job */
6963  if( glbest < est )
6964  duration -= (est - glbest);
6965 
6966  if( glblct > lct )
6967  duration -= (glblct - lct);
6968 
6969  if( duration > 0 )
6970  {
6971  glbenery += nodedata->demand * duration;
6972 
6973  if( explanation != NULL )
6974  explanation[nodedata->idx] = TRUE;
6975  }
6976  }
6977 
6978  /* analyze the overload */
6979  SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
6980  conshdlrdata->usebdwidening, initialized, explanation) );
6981  }
6982  else if( ninsertcands > 1 && conshdlrdata->efinfer )
6983  {
6984  /* if we have more than one job insterted and edge-finding should be performed we do it */
6985  SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
6986  propest, shift, initialized, explanation, nchgbds, cutoff) );
6987  }
6988 
6989  /* free the search nodes data */
6990  for( j = nnodedatas - 1; j >= 0; --j )
6991  {
6992  freeNodedata(scip, &nodedatas[j]);
6993  }
6994 
6995  /* free theta tree */
6996  SCIPbtFree(&tree);
6997 
6998  /* free buffer arrays */
6999  SCIPfreeBufferArray(scip, &leaves);
7000  SCIPfreeBufferArray(scip, &nodedatas);
7001 
7002  return SCIP_OKAY;
7003 }
7004 
7005 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7006  *
7007  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7008  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7009  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7010  */
7011 static
7013  SCIP* scip, /**< SCIP data structure */
7014  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7015  int nvars, /**< number of start time variables (activities) */
7016  SCIP_VAR** vars, /**< array of start time variables */
7017  int* durations, /**< array of durations */
7018  int* demands, /**< array of demands */
7019  int capacity, /**< cumulative capacity */
7020  int hmin, /**< left bound of time axis to be considered (including hmin) */
7021  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7022  SCIP_CONS* cons, /**< constraint which is propagated */
7023  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7024  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7025  int* nchgbds, /**< pointer to store the number of bound changes */
7026  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7027  )
7028 {
7029  /* check if a cutoff was already detected */
7030  if( (*cutoff) )
7031  return SCIP_OKAY;
7032 
7033  /* check if at least the basic overload checking should be preformed */
7034  if( !conshdlrdata->efcheck )
7035  return SCIP_OKAY;
7036 
7037  /* check for overload, which may result in a cutoff */
7038  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7039  cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7040 
7041  /* check if a cutoff was detected */
7042  if( (*cutoff) )
7043  return SCIP_OKAY;
7044 
7045  /* check if bound should be infer */
7046  if( !conshdlrdata->efinfer )
7047  return SCIP_OKAY;
7048 
7049  /* check for overload, which may result in a cutoff */
7050  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7051  cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7052 
7053  return SCIP_OKAY;
7054 }
7055 
7056 /** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7057  * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7058  * event points
7059  */
7060 static
7062  SCIP* scip, /**< SCIP data structure */
7063  int nvars, /**< number of start time variables (activities) */
7064  SCIP_VAR** vars, /**< array of start time variables */
7065  int* durations, /**< array of durations */
7066  int* demands, /**< array of demands */
7067  int capacity, /**< cumulative capacity */
7068  int hmin, /**< left bound of time axis to be considered (including hmin) */
7069  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7070  SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7071  )
7072 {
7073 
7074  SCIP_VAR* var;
7075  int* starttimes; /* stores when each job is starting */
7076  int* endtimes; /* stores when each job ends */
7077  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7078  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7079 
7080  int lb;
7081  int ub;
7082  int freecapacity; /* remaining capacity */
7083  int curtime; /* point in time which we are just checking */
7084  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7085  int njobs;
7086  int j;
7087 
7088  assert(scip != NULL);
7089  assert(redundant != NULL);
7090 
7091  (*redundant) = TRUE;
7092 
7093  /* if no activities are associated with this cumulative then this constraint is redundant */
7094  if( nvars == 0 )
7095  return SCIP_OKAY;
7096 
7097  assert(vars != NULL);
7098 
7099  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7100  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7101  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7102  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7103 
7104  njobs = 0;
7105 
7106  /* assign variables, start and endpoints to arrays */
7107  for( j = 0; j < nvars; ++j )
7108  {
7109  assert(durations[j] > 0);
7110  assert(demands[j] > 0);
7111 
7112  var = vars[j];
7113  assert(var != NULL);
7114 
7115  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7116  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7117 
7118  /* check if jobs runs completely outside of the effective time horizon */
7119  if( lb >= hmax || ub + durations[j] <= hmin )
7120  continue;
7121 
7122  starttimes[njobs] = MAX(lb, hmin);
7123  startindices[njobs] = j;
7124 
7125  endtimes[njobs] = MIN(ub + durations[j], hmax);
7126  endindices[njobs] = j;
7127  assert(starttimes[njobs] <= endtimes[njobs]);
7128  njobs++;
7129  }
7130 
7131  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7132  SCIPsortIntInt(starttimes, startindices, njobs);
7133  SCIPsortIntInt(endtimes, endindices, njobs);
7134 
7135  endindex = 0;
7136  freecapacity = capacity;
7137 
7138  /* check each start point of a job whether the capacity is violated or not */
7139  for( j = 0; j < njobs; ++j )
7140  {
7141  curtime = starttimes[j];
7142 
7143  /* stop checking, if time point is above hmax */
7144  if( curtime >= hmax )
7145  break;
7146 
7147  /* subtract all capacity needed up to this point */
7148  freecapacity -= demands[startindices[j]];
7149  while( j+1 < njobs && starttimes[j+1] == curtime )
7150  {
7151  ++j;
7152  freecapacity -= demands[startindices[j]];
7153  }
7154 
7155  /* free all capacity usages of jobs the are no longer running */
7156  while( endtimes[endindex] <= curtime )
7157  {
7158  freecapacity += demands[endindices[endindex]];
7159  ++endindex;
7160  }
7161  assert(freecapacity <= capacity);
7162 
7163  /* check freecapacity to be smaller than zero */
7164  if( freecapacity < 0 && curtime >= hmin )
7165  {
7166  (*redundant) = FALSE;
7167  break;
7168  }
7169  } /*lint --e{850}*/
7170 
7171  /* free all buffer arrays */
7172  SCIPfreeBufferArray(scip, &endindices);
7173  SCIPfreeBufferArray(scip, &startindices);
7174  SCIPfreeBufferArray(scip, &endtimes);
7175  SCIPfreeBufferArray(scip, &starttimes);
7176 
7177  return SCIP_OKAY;
7178 }
7179 
7180 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7181  * completion time
7182  */
7183 static
7185  SCIP* scip, /**< SCIP data structure */
7186  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7187  SCIP_PROFILE* profile, /**< resource profile */
7188  int nvars, /**< number of variables (jobs) */
7189  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7190  int* durations, /**< array containing corresponding durations */
7191  int* demands, /**< array containing corresponding demands */
7192  int capacity, /**< cumulative capacity */
7193  int hmin, /**< left bound of time axis to be considered (including hmin) */
7194  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7195  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7196  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7197  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7198  )
7199 {
7200  int v;
7201 
7202  /* insert all cores */
7203  for( v = 0; v < nvars; ++v )
7204  {
7205  SCIP_VAR* var;
7206  SCIP_Bool infeasible;
7207  int duration;
7208  int demand;
7209  int begin;
7210  int end;
7211  int est;
7212  int lst;
7213  int pos;
7214 
7215  var = vars[v];
7216  assert(var != NULL);
7217  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(var)));
7218  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(var)));
7219 
7220  duration = durations[v];
7221  assert(duration > 0);
7222 
7223  demand = demands[v];
7224  assert(demand > 0);
7225 
7226  /* collect earliest and latest start time */
7227  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7228  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7229 
7230  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7231  if( lst + duration <= hmin || est >= hmax )
7232  continue;
7233 
7234  /* compute core interval w.r.t. effective time horizon */
7235  begin = MAX(hmin, lst);
7236  end = MIN(hmax, est + duration);
7237 
7238  /* check if a core exists */
7239  if( begin >= end )
7240  continue;
7241 
7242  SCIPdebugMessage("variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7243  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7244 
7245  /* insert the core into core resource profile (complexity O(log n)) */
7246  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7247 
7248  /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7249  if( infeasible )
7250  {
7251  assert(begin <= SCIPprofileGetTime(profile, pos));
7252  assert(end > SCIPprofileGetTime(profile, pos));
7253 
7254  /* use conflict analysis to analysis the core insertion which was infeasible */
7255  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7256  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7257 
7258  if( explanation != NULL )
7259  explanation[v] = TRUE;
7260 
7261  (*cutoff) = TRUE;
7262 
7263  /* for the statistic we count the number of times a cutoff was detected due the time-time */
7264  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
7265 
7266  break;
7267  }
7268  }
7269 
7270  return SCIP_OKAY;
7271 }
7272 
7273 /** propagate the cumulative condition */
7274 static
7276  SCIP* scip, /**< SCIP data structure */
7277  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7278  int nvars, /**< number of start time variables (activities) */
7279  SCIP_VAR** vars, /**< array of start time variables */
7280  int* durations, /**< array of durations */
7281  int* demands, /**< array of demands */
7282  int capacity, /**< cumulative capacity */
7283  int hmin, /**< left bound of time axis to be considered (including hmin) */
7284  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7285  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7286  int* nchgbds, /**< pointer to store the number of bound changes */
7287  SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7288  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7289  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7290  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7291  )
7292 {
7293  SCIP_PROFILE* profile;
7294 
7295  assert(nchgbds != NULL);
7296  assert(initialized != NULL);
7297  assert(cutoff != NULL);
7298  assert((*cutoff) == FALSE);
7299 
7300  /**@todo avoid always sorting the variable array */
7301 
7302  /* check if the constraint is redundant */
7303  SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7304 
7305  if( *redundant )
7306  return SCIP_OKAY;
7307 
7308  /* create an empty resource profile for profiling the cores of the jobs */
7309  SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7310 
7311  /* create core profile (compulsory parts) */
7312  SCIP_CALL( createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7313  initialized, explanation, cutoff) );
7314 
7315  /* propagate the job cores until nothing else can be detected */
7316  SCIP_CALL( propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7317  nchgbds, initialized, explanation, cutoff) );
7318 
7319  /* run edge finding propagator */
7320  SCIP_CALL( propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7321  cons, initialized, explanation, nchgbds, cutoff) );
7322 
7323  /* run time-table edge-finding propagator */
7324  SCIP_CALL( propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7325  nchgbds, initialized, explanation, cutoff) );
7326 
7327  /* free resource profile */
7328  SCIPprofileFree(&profile);
7329 
7330  return SCIP_OKAY;
7331 }
7332 
7333 /** propagate the cumulative constraint */
7334 static
7336  SCIP* scip, /**< SCIP data structure */
7337  SCIP_CONS* cons, /**< constraint to propagate */
7338  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7339  int* nchgbds, /**< pointer to store the number of bound changes */
7340  int* ndelconss, /**< pointer to store the number of deleted constraints */
7341  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7342  )
7343 {
7344  SCIP_CONSDATA* consdata;
7345  SCIP_Bool initialized;
7346  SCIP_Bool redundant;
7347  int oldnchgbds;
7348 
7349  assert(scip != NULL);
7350  assert(cons != NULL);
7351 
7352  consdata = SCIPconsGetData(cons);
7353  assert(consdata != NULL);
7354 
7355  oldnchgbds = *nchgbds;
7356  initialized = FALSE;
7357  redundant = FALSE;
7358 
7359  if( SCIPconsIsDeleted(cons) )
7360  {
7361  assert(SCIPinProbing(scip));
7362  return SCIP_OKAY;
7363  }
7364 
7365  /* if the constraint marked to be propagated, do nothing */
7366  if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7367  return SCIP_OKAY;
7368 
7369  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata,
7370  consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7371  consdata->hmin, consdata->hmax, cons,
7372  nchgbds, &redundant, &initialized, NULL, cutoff) );
7373 
7374  if( redundant )
7375  {
7376  SCIPdebugMessage("%s deletes cumulative constraint <%s> since it is redundant\n",
7377  SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7378 
7379  if( !SCIPinProbing(scip) )
7380  {
7381  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7382  (*ndelconss)++;
7383  }
7384  }
7385  else
7386  {
7387  if( initialized )
7388  {
7389  /* run conflict analysis since it was initialized */
7390  assert(*cutoff == TRUE);
7391  SCIPdebugMessage("start conflict analysis\n");
7392  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7393  }
7394 
7395  /* if successful, reset age of constraint */
7396  if( *cutoff || *nchgbds > oldnchgbds )
7397  {
7398  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7399  }
7400  else
7401  {
7402  /* mark the constraint to be propagated */
7403  consdata->propagated = TRUE;
7404  }
7405  }
7406 
7407  return SCIP_OKAY;
7408 }
7409 
7410 /** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7411  * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7412  * be realize as domain reduction. Otherwise we do nothing
7413  */
7414 static
7416  SCIP* scip, /**< SCIP data structure */
7417  SCIP_VAR** vars, /**< problem variables */
7418  int nvars, /**< number of problem variables */
7419  int probingpos, /**< variable number to apply probing on */
7420  SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7421  SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7422  SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7423  SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7424  SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7425  SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7426  SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7427  SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7428  SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7429  SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7430  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7431  SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7432  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7433  )
7434 {
7435  SCIP_VAR* var;
7436  SCIP_Bool tightened;
7437 
7438  assert(probingpos >= 0);
7439  assert(probingpos < nvars);
7440  assert(success != NULL);
7441  assert(cutoff != NULL);
7442 
7443  var = vars[probingpos];
7444  assert(var != NULL);
7445  assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7446  assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7447  assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7448  assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7449 
7450  (*success) = FALSE;
7451 
7452  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7453  return SCIP_OKAY;
7454 
7455  /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7456  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7457  leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7458 
7459  if( (*cutoff) )
7460  {
7461  /* note that cutoff may occur if presolving has not been executed fully */
7462  SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7463 
7464  if( tightened )
7465  {
7466  (*success) =TRUE;
7467  (*nfixedvars)++;
7468  }
7469 
7470  return SCIP_OKAY;
7471  }
7472 
7473  /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7474  * presolving has not been executed fully
7475  */
7476  if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7477  {
7478  /* note that cutoff may occur if presolving has not been executed fully */
7479  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7480 
7481  if( tightened )
7482  {
7483  (*success) = TRUE;
7484  (*nfixedvars)++;
7485  }
7486 
7487  return SCIP_OKAY;
7488  }
7489 
7490  /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7491  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7492  rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7493 
7494  if( (*cutoff) )
7495  {
7496  /* note that cutoff may occur if presolving has not been executed fully */
7497  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7498 
7499  if( tightened )
7500  {
7501  (*success) =TRUE;
7502  (*nfixedvars)++;
7503  }
7504 
7505  return SCIP_OKAY;
7506  }
7507 
7508  return SCIP_OKAY;
7509 }
7510 
7511 /** is it possible, to round variable down w.r.t. objective function */
7512 static
7514  SCIP* scip, /**< SCIP data structure */
7515  SCIP_VAR* var, /**< problem variable */
7516  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7517  )
7518 {
7519  SCIP_Real objval;
7520  int scalar;
7521 
7522  assert(roundable != NULL);
7523 
7524  *roundable = TRUE;
7525 
7526  /* a fixed variable can be definition always be safely rounded */
7528  return SCIP_OKAY;
7529 
7530  /* in case the variable is not active we need to check the object coefficient of the active variable */
7531  if( !SCIPvarIsActive(var) )
7532  {
7533  SCIP_VAR* actvar;
7534  int constant;
7535 
7536  actvar = var;
7537 
7538  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7539  assert(scalar != 0);
7540 
7541  objval = scalar * SCIPvarGetObj(actvar);
7542  }
7543  else
7544  {
7545  scalar = 1;
7546  objval = SCIPvarGetObj(var);
7547  }
7548 
7549  /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7550  * (the transformed problem is always a minimization problem)
7551  *
7552  * @note that we need to check this condition w.r.t. active variable space
7553  */
7554  if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7555  *roundable = FALSE;
7556 
7557  return SCIP_OKAY;
7558 }
7559 
7560 /** is it possible, to round variable up w.r.t. objective function */
7561 static
7563  SCIP* scip, /**< SCIP data structure */
7564  SCIP_VAR* var, /**< problem variable */
7565  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7566  )
7567 {
7568  SCIP_Real objval;
7569  int scalar;
7570 
7571  assert(roundable != NULL);
7572 
7573  *roundable = TRUE;
7574 
7575  /* a fixed variable can be definition always be safely rounded */
7577  return SCIP_OKAY;
7578 
7579  /* in case the variable is not active we need to check the object coefficient of the active variable */
7580  if( !SCIPvarIsActive(var) )
7581  {
7582  SCIP_VAR* actvar;
7583  int constant;
7584 
7585  actvar = var;
7586 
7587  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7588  assert(scalar != 0);
7589 
7590  objval = scalar * SCIPvarGetObj(actvar);
7591  }
7592  else
7593  {
7594  scalar = 1;
7595  objval = SCIPvarGetObj(var);
7596  }
7597 
7598  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7599  * (the transformed problem is always a minimization problem)
7600  *
7601  * @note that we need to check this condition w.r.t. active variable space
7602  */
7603  if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7604  *roundable = FALSE;
7605 
7606  return SCIP_OKAY;
7607 }
7608 
7609 /** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7610  * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7611  * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7612  * the only one locking this variable in the corresponding direction.
7613  */
7614 static
7616  SCIP* scip, /**< SCIP data structure */
7617  SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7618  int nconss, /**< number of cumulative constraints */
7619  SCIP_Bool local, /**< use local bounds effective horizon? */
7620  int* alternativelbs, /**< alternative lower bounds */
7621  int* alternativeubs, /**< alternative lower bounds */
7622  int* downlocks, /**< number of constraints with down lock participating by the computation */
7623  int* uplocks /**< number of constraints with up lock participating by the computation */
7624  )
7625 {
7626  int nvars;
7627  int c;
7628  int v;
7629 
7630  for( c = 0; c < nconss; ++c )
7631  {
7632  SCIP_CONSDATA* consdata;
7633  SCIP_CONS* cons;
7634  SCIP_VAR* var;
7635  int hmin;
7636  int hmax;
7637 
7638  cons = conss[c];
7639  assert(cons != NULL);
7640 
7641  /* ignore constraints which are already deletet and those which are not check constraints */
7642  if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7643  continue;
7644 
7645  consdata = SCIPconsGetData(cons);
7646  assert(consdata != NULL);
7647  assert(consdata->nvars > 1);
7648 
7649  /* compute the hmin and hmax */
7650  if( local )
7651  {
7652  SCIP_PROFILE* profile;
7653 
7654  /* create empty resource profile with infinity resource capacity */
7655  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7656 
7657  /* create worst case resource profile */
7658  SCIP_CALL( SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands) );
7659 
7660  hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7661  hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7662 
7663  /* free worst case profile */
7664  SCIPprofileFree(&profile);
7665  }
7666  else
7667  {
7668  hmin = consdata->hmin;
7669  hmax = consdata->hmax;
7670  }
7671 
7672  consdata = SCIPconsGetData(cons);
7673  assert(consdata != NULL);
7674 
7675  nvars = consdata->nvars;
7676 
7677  for( v = 0; v < nvars; ++v )
7678  {
7679  int scalar;
7680  int constant;
7681  int idx;
7682 
7683  var = consdata->vars[v];
7684  assert(var != NULL);
7685 
7686  /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7687  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR);
7688 
7689  /* ignore variable locally fixed variables */
7690  if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7691  continue;
7692 
7693 
7694  SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7695  idx = SCIPvarGetProbindex(var);
7696  assert(idx >= 0);
7697 
7698  /* first check lower bound fixing */
7699  if( consdata->downlocks[v] )
7700  {
7701  int ect;
7702  int est;
7703 
7704  /* the variable has a down locked */
7705  est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7706  ect = est + consdata->durations[v];
7707 
7708  if( ect <= hmin || hmin >= hmax )
7709  downlocks[idx]++;
7710  else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7711  {
7712  alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7713  downlocks[idx]++;
7714  }
7715  }
7716 
7717  /* second check upper bound fixing */
7718  if( consdata->uplocks[v] )
7719  {
7720  int duration;
7721  int lct;
7722  int lst;
7723 
7724  duration = consdata->durations[v];
7725 
7726  /* the variable has a up lock locked */
7727  lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7728  lct = lst + duration;
7729 
7730  if( lst >= hmax || hmin >= hmax )
7731  uplocks[idx]++;
7732  else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7733  {
7734  alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7735  uplocks[idx]++;
7736  }
7737  }
7738  }
7739  }
7740 
7741  return SCIP_OKAY;
7742 }
7743 
7744 /** apply all fixings which are given by the alternative bounds */
7745 static
7747  SCIP* scip, /**< SCIP data structure */
7748  SCIP_VAR** vars, /**< array of active variables */
7749  int nvars, /**< number of active variables */
7750  int* alternativelbs, /**< alternative lower bounds */
7751  int* alternativeubs, /**< alternative lower bounds */
7752  int* downlocks, /**< number of constraints with down lock participating by the computation */
7753  int* uplocks, /**< number of constraints with up lock participating by the computation */
7754  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7755  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7756  )
7757 {
7758  SCIP_Real* downimpllbs;
7759  SCIP_Real* downimplubs;
7760  SCIP_Real* downproplbs;
7761  SCIP_Real* downpropubs;
7762  SCIP_Real* upimpllbs;
7763  SCIP_Real* upimplubs;
7764  SCIP_Real* upproplbs;
7765  SCIP_Real* uppropubs;
7766  int v;
7767 
7768  /* get temporary memory for storing probing results */
7769  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7770  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7771  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7772  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7773  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7774  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7775  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7776  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7777 
7778  for( v = 0; v < nvars; ++v )
7779  {
7780  SCIP_VAR* var;
7781  SCIP_Bool infeasible;
7782  SCIP_Bool fixed;
7783  SCIP_Bool roundable;
7784  int ub;
7785  int lb;
7786 
7787  var = vars[v];
7788  assert(var != NULL);
7789 
7790  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7791  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7792 
7793  /* ignore fixed variables */
7794  if( ub - lb <= 0 )
7795  continue;
7796 
7797 
7798  if( SCIPvarGetNLocksDown(var) == downlocks[v] )
7799  {
7800  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7801 
7802  if( roundable )
7803  {
7804  if( alternativelbs[v] > ub )
7805  {
7806  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7807  assert(!infeasible);
7808  assert(fixed);
7809 
7810  (*nfixedvars)++;
7811 
7812  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7813  * constraints
7814  */
7815  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7816  }
7817  else
7818  {
7819  SCIP_Bool success;
7820 
7821  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7822  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7823  * infeasible we can apply the dual reduction; otherwise we do nothing
7824  */
7825  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7826  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7827  nfixedvars, &success, cutoff) );
7828 
7829  if( success )
7830  {
7831  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7832  }
7833 
7834  }
7835  }
7836  }
7837 
7838  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7839  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7840 
7841  /* ignore fixed variables */
7842  if( ub - lb <= 0 )
7843  continue;
7844 
7845  if( SCIPvarGetNLocksUp(var) == uplocks[v] )
7846  {
7847  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7848 
7849  if( roundable )
7850  {
7851  if( alternativeubs[v] < lb )
7852  {
7853  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
7854  assert(!infeasible);
7855  assert(fixed);
7856 
7857  (*nfixedvars)++;
7858 
7859  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7860  * constraints
7861  */
7862  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7863  }
7864  else
7865  {
7866  SCIP_Bool success;
7867 
7868  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7869  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7870  * infeasible we can apply the dual reduction; otherwise we do nothing
7871  */
7872  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
7873  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7874  nfixedvars, &success, cutoff) );
7875 
7876  if( success )
7877  {
7878  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7879  }
7880  }
7881  }
7882  }
7883  }
7884 
7885  /* free temporary memory */
7886  SCIPfreeBufferArray(scip, &uppropubs);
7887  SCIPfreeBufferArray(scip, &upproplbs);
7888  SCIPfreeBufferArray(scip, &upimplubs);
7889  SCIPfreeBufferArray(scip, &upimpllbs);
7890  SCIPfreeBufferArray(scip, &downpropubs);
7891  SCIPfreeBufferArray(scip, &downproplbs);
7892  SCIPfreeBufferArray(scip, &downimplubs);
7893  SCIPfreeBufferArray(scip, &downimpllbs);
7894 
7895  return SCIP_OKAY;
7896 }
7897 
7898 /** propagate all constraints together */
7899 static
7901  SCIP* scip, /**< SCIP data structure */
7902  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7903  SCIP_CONS** conss, /**< all cumulative constraint */
7904  int nconss, /**< number of cumulative constraints */
7905  SCIP_Bool local, /**< use local bounds effective horizon? */
7906  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7907  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
7908  SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
7909  )
7910 { /*lint --e{715}*/
7911  SCIP_VAR** vars;
7912  int* downlocks;
7913  int* uplocks;
7914  int* alternativelbs;
7915  int* alternativeubs;
7916  int oldnfixedvars;
7917  int nvars;
7918  int v;
7919 
7920  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7921  return SCIP_OKAY;
7922 
7923  nvars = SCIPgetNVars(scip);
7924  oldnfixedvars = *nfixedvars;
7925 
7926  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) );
7927  SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
7928  SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
7929  SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
7930  SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
7931 
7932  /* initialize arrays */
7933  for( v = 0; v < nvars; ++v )
7934  {
7935  downlocks[v] = 0;
7936  uplocks[v] = 0;
7937  alternativelbs[v] = INT_MAX;
7938  alternativeubs[v] = INT_MIN;
7939  }
7940 
7941  /* compute alternative bounds */
7942  SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
7943 
7944  /* apply fixing which result of the alternative bounds directly */
7945  SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
7946  nfixedvars, cutoff) );
7947 
7948  if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
7949  {
7950  SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
7951  }
7952 
7953  /* free all buffers */
7954  SCIPfreeBufferArray(scip, &alternativeubs);
7955  SCIPfreeBufferArray(scip, &alternativelbs);
7956  SCIPfreeBufferArray(scip, &uplocks);
7957  SCIPfreeBufferArray(scip, &downlocks);
7958  SCIPfreeBufferArray(scip, &vars);
7959 
7960  return SCIP_OKAY;
7961 }
7962 
7963 /**@} */
7964 
7965 /**@name Linear relaxations
7966  *
7967  * @{
7968  */
7969 
7970 /** creates covering cuts for jobs violating resource constraints */
7971 static
7973  SCIP* scip, /**< SCIP data structure */
7974  SCIP_CONS* cons, /**< constraint to be checked */
7975  int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
7976  int time /**< at this point in time covering constraints are valid */
7977  )
7978 {
7979  SCIP_CONSDATA* consdata;
7980  SCIP_ROW* row;
7981  int* flexibleids;
7982  int* demands;
7983 
7984  char rowname[SCIP_MAXSTRLEN];
7985 
7986  int remainingcap;
7987  int smallcoversize; /* size of a small cover */
7988  int bigcoversize; /* size of a big cover */
7989  int nvars;
7990 
7991  int nflexible;
7992  int sumdemand; /* demand of all jobs up to a certain index */
7993  int j;
7994 
7995  assert(cons != NULL);
7996 
7997  /* get constraint data structure */
7998  consdata = SCIPconsGetData(cons);
7999  assert(consdata != NULL );
8000 
8001  nvars = consdata->nvars;
8002 
8003  /* sort jobs according to demands */
8004  SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8005  SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8006 
8007  nflexible = 0;
8008  remainingcap = consdata->capacity;
8009 
8010  /* get all jobs intersecting point 'time' with their bounds */
8011  for( j = 0; j < nvars; ++j )
8012  {
8013  int ub;
8014 
8015  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8016 
8017  /* only add jobs to array if they intersect with point 'time' */
8018  if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8019  {
8020  /* if job is fixed, capacity has to be decreased */
8021  if( startvalues[j] == ub )
8022  {
8023  remainingcap -= consdata->demands[j];
8024  }
8025  else
8026  {
8027  demands[nflexible] = consdata->demands[j];
8028  flexibleids[nflexible] = j;
8029  ++nflexible;
8030  }
8031  }
8032  }
8033  assert(remainingcap >= 0);
8034 
8035  /* sort demands and job ids */
8036  SCIPsortIntInt(demands, flexibleids, nflexible);
8037 
8038  /*
8039  * version 1:
8040  * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8041  * erzeuge cover constraint
8042  *
8043  */
8044 
8045  /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8046  sumdemand = 0;
8047  j = 0;
8048 
8049  while( j < nflexible && sumdemand <= remainingcap )
8050  {
8051  sumdemand += demands[j];
8052  j++;
8053  }
8054 
8055  /* j jobs form a conflict, set coversize to 'j - 1' */
8056  bigcoversize = j-1;
8057  assert(sumdemand > remainingcap);
8058  assert(bigcoversize < nflexible);
8059 
8060  /* - create a row for all jobs and their binary variables.
8061  * - at most coversize many binary variables of jobs can be set to one
8062  */
8063 
8064  /* construct row name */
8065  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8066  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8067  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8068  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8069 
8070  for( j = 0; j < nflexible; ++j )
8071  {
8072  SCIP_VAR** binvars;
8073  int* vals;
8074  int nbinvars;
8075  int idx;
8076  int start;
8077  int end;
8078  int lb;
8079  int ub;
8080  int b;
8081 
8082  idx = flexibleids[j];
8083 
8084  /* get and add binvars into var array */
8085  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8086  assert(nbinvars != 0);
8087 
8088  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8089  assert(vals != NULL);
8090 
8091  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8092  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8093 
8094  /* compute start and finishing time */
8095  start = time - consdata->durations[idx] + 1;
8096  end = MIN(time, ub);
8097 
8098  /* add all neccessary binary variables */
8099  for( b = 0; b < nbinvars; ++b )
8100  {
8101  if( vals[b] < start || vals[b] < lb )
8102  continue;
8103 
8104  if( vals[b] > end )
8105  break;
8106 
8107  assert(binvars[b] != NULL);
8108  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8109  }
8110  }
8111 
8112  /* insert and release row */
8113  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8114 
8115  if( consdata->bcoverrowssize == 0 )
8116  {
8117  consdata->bcoverrowssize = 10;
8118  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8119  }
8120  if( consdata->nbcoverrows == consdata->bcoverrowssize )
8121  {
8122  consdata->bcoverrowssize *= 2;
8123  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8124  }
8125 
8126  consdata->bcoverrows[consdata->nbcoverrows] = row;
8127  consdata->nbcoverrows++;
8128 
8129  /*
8130  * version 2:
8131  * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8132  * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8133  */
8134  /* find maximum number of jobs that can run in parallel (= coversize -1) */
8135  sumdemand = 0;
8136  j = nflexible -1;
8137  while( sumdemand <= remainingcap )
8138  {
8139  assert(j >= 0);
8140  sumdemand += demands[j];
8141  j--;
8142  }
8143 
8144  smallcoversize = nflexible - (j + 1) - 1;
8145  while( j > 0 && demands[j] == demands[nflexible-1] )
8146  --j;
8147 
8148  assert(smallcoversize < nflexible);
8149 
8150  if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8151  {
8152  /* construct row name */
8153  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8154  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8155  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8156  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8157 
8158  /* filter binary variables for each unfixed job */
8159  for( j = j + 1; j < nflexible; ++j )
8160  {
8161  SCIP_VAR** binvars;
8162  int* vals;
8163  int nbinvars;
8164  int idx;
8165  int start;
8166  int end;
8167  int lb;
8168  int ub;
8169  int b;
8170 
8171  idx = flexibleids[j];
8172 
8173  /* get and add binvars into var array */
8174  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8175  assert(nbinvars != 0);
8176 
8177  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8178  assert(vals != NULL);
8179 
8180  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8181  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8182 
8183  /* compute start and finishing time */
8184  start = time - consdata->durations[idx] + 1;
8185  end = MIN(time, ub);
8186 
8187  /* add all neccessary binary variables */
8188  for( b = 0; b < nbinvars; ++b )
8189  {
8190  if( vals[b] < start || vals[b] < lb )
8191  continue;
8192 
8193  if( vals[b] > end )
8194  break;
8195 
8196  assert(binvars[b] != NULL);
8197  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8198  }
8199  }
8200 
8201  /* insert and release row */
8202  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8203  if( consdata->scoverrowssize == 0 )
8204  {
8205  consdata->scoverrowssize = 10;
8206  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8207  }
8208  if( consdata->nscoverrows == consdata->scoverrowssize )
8209  {
8210  consdata->scoverrowssize *= 2;
8211  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8212  }
8213 
8214  consdata->scoverrows[consdata->nscoverrows] = row;
8215  consdata->nscoverrows++;
8216  }
8217 
8218  /* free buffer arrays */
8219  SCIPfreeBufferArray(scip, &flexibleids);
8220  SCIPfreeBufferArray(scip, &demands);
8221 
8222  return SCIP_OKAY;
8223 }
8224 
8225 /** method to construct cover cuts for all points in time */
8226 static
8228  SCIP* scip, /**< SCIP data structure */
8229  SCIP_CONS* cons /**< constraint to be separated */
8230  )
8231 {
8232  SCIP_CONSDATA* consdata;
8233 
8234  int* startvalues; /* stores when each job is starting */
8235  int* endvalues; /* stores when each job ends */
8236  int* startvaluessorted; /* stores when each job is starting */
8237  int* endvaluessorted; /* stores when each job ends */
8238  int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8239  int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8240 
8241  int nvars; /* number of jobs for this constraint */
8242  int freecapacity; /* remaining capacity */
8243  int curtime; /* point in time which we are just checking */
8244  int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8245 
8246  int hmin;
8247  int hmax;
8248 
8249  int j;
8250  int t;
8251 
8252  assert(scip != NULL);
8253  assert(cons != NULL);
8254 
8255  consdata = SCIPconsGetData(cons);
8256  assert(consdata != NULL);
8257 
8258  /* if no activities are associated with this resource then this constraint is redundant */
8259  if( consdata->vars == NULL )
8260  return SCIP_OKAY;
8261 
8262  nvars = consdata->nvars;
8263  hmin = consdata->hmin;
8264  hmax = consdata->hmax;
8265 
8266  SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8267  SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8268  SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8269  SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8270  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8271  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8272 
8273  /* assign start and endpoints to arrays */
8274  for ( j = 0; j < nvars; ++j )
8275  {
8276  startvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8277  startvaluessorted[j] = startvalues[j];
8278 
8279  endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8280  endvaluessorted[j] = endvalues[j];
8281 
8282  startindices[j] = j;
8283  endindices[j] = j;
8284  }
8285 
8286  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8287  * (and sort the indices in the same way) */
8288  SCIPsortIntInt(startvaluessorted, startindices, nvars);
8289  SCIPsortIntInt(endvaluessorted, endindices, nvars);
8290 
8291  endidx = 0;
8292  freecapacity = consdata->capacity;
8293 
8294  /* check each startpoint of a job whether the capacity is kept or not */
8295  for( j = 0; j < nvars; ++j )
8296  {
8297  curtime = startvaluessorted[j];
8298  if( curtime >= hmax )
8299  break;
8300 
8301  /* subtract all capacity needed up to this point */
8302  freecapacity -= consdata->demands[startindices[j]];
8303 
8304  while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8305  {
8306  ++j;
8307  freecapacity -= consdata->demands[startindices[j]];
8308  }
8309 
8310  /* free all capacity usages of jobs the are no longer running */
8311  while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8312  {
8313  freecapacity += consdata->demands[endindices[endidx]];
8314  ++endidx;
8315  }
8316 
8317  assert(freecapacity <= consdata->capacity);
8318  assert(endidx <= nvars);
8319 
8320  /* --> endindex - points to the next job which will finish
8321  * j - points to the last job that has been released
8322  */
8323 
8324 
8325  /* check freecapacity to be smaller than zero
8326  * then we will add cover constraints to the MIP
8327  */
8328  if( freecapacity < 0 && curtime >= hmin )
8329  {
8330  int nextprofilechange;
8331 
8332  /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8333  if( j < nvars-1 )
8334  nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8335  else
8336  nextprofilechange = endvaluessorted[endidx];
8337 
8338  nextprofilechange = MIN(nextprofilechange, hmax);
8339 
8340  for( t = curtime; t < nextprofilechange; ++t )
8341  {
8342  SCIPdebugMessage("add cover constraint for time %d\n", curtime);
8343 
8344  /* create covering constraint */
8345  SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8346 
8347  }
8348  } /* end if freecapacity > 0 */
8349 
8350  } /*lint --e{850}*/
8351 
8352  consdata->covercuts = TRUE;
8353 
8354  /* free all buffer arrays */
8355  SCIPfreeBufferArray(scip, &endindices);
8356  SCIPfreeBufferArray(scip, &startindices);
8357  SCIPfreeBufferArray(scip, &endvaluessorted);
8358  SCIPfreeBufferArray(scip, &startvaluessorted);
8359  SCIPfreeBufferArray(scip, &endvalues);
8360  SCIPfreeBufferArray(scip, &startvalues);
8361 
8362  return SCIP_OKAY;
8363 }
8364 
8365 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8366  * constraint
8367  */
8368 static
8370  SCIP* scip, /**< SCIP data structure */
8371  SCIP_CONS* cons, /**< constraint to be checked */
8372  int* startindices, /**< permutation with rspect to the start times */
8373  int curtime, /**< current point in time */
8374  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8375  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8376  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8377  )
8378 {
8379  SCIP_CONSDATA* consdata;
8380  SCIP_VAR** binvars;
8381  int* coefs;
8382  int nbinvars;
8383  char name[SCIP_MAXSTRLEN];
8384  int capacity;
8385  int b;
8386 
8387  assert(nstarted > nfinished);
8388 
8389  consdata = SCIPconsGetData(cons);
8390  assert(consdata != NULL);
8391  assert(consdata->nvars > 0);
8392 
8393  capacity = consdata->capacity;
8394  assert(capacity > 0);
8395 
8396  nbinvars = 0;
8397  SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8398 
8399  /* construct row name */
8400  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8401 
8402  if( cutsasconss )
8403  {
8404  SCIP_CONS* lincons;
8405 
8406  /* create knapsack constraint for the given time point */
8407  SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8408  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) );
8409 
8410  for( b = 0; b < nbinvars; ++b )
8411  {
8412  SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8413  }
8414 
8415  /* add and release the new constraint */
8416  SCIP_CALL( SCIPaddCons(scip, lincons) );
8417  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8418  }
8419  else
8420  {
8421  SCIP_ROW* row;
8422 
8423  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8424  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8425 
8426  for( b = 0; b < nbinvars; ++b )
8427  {
8428  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8429  }
8430 
8431  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8432  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8433 
8434  if( consdata->demandrowssize == 0 )
8435  {
8436  consdata->demandrowssize = 10;
8437  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8438  }
8439  if( consdata->ndemandrows == consdata->demandrowssize )
8440  {
8441  consdata->demandrowssize *= 2;
8442  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8443  }
8444 
8445  consdata->demandrows[consdata->ndemandrows] = row;
8446  consdata->ndemandrows++;
8447  }
8448 
8449  SCIPfreeBufferArrayNull(scip, &binvars);
8450  SCIPfreeBufferArrayNull(scip, &coefs);
8451 
8452  return SCIP_OKAY;
8453 }
8454 
8455 /** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8456  * row
8457  */
8458 static
8460  SCIP* scip, /**< SCIP data structure */
8461  SCIP_CONS* cons, /**< constraint to be checked */
8462  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8463  )
8464 {
8465  SCIP_CONSDATA* consdata;
8466 
8467  int* starttimes; /* stores when each job is starting */
8468  int* endtimes; /* stores when each job ends */
8469  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8470  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8471 
8472  int nvars; /* number of activities for this constraint */
8473  int freecapacity; /* remaining capacity */
8474  int curtime; /* point in time which we are just checking */
8475  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8476 
8477  int hmin;
8478  int hmax;
8479 
8480  int j;
8481 
8482  assert(scip != NULL);
8483  assert(cons != NULL);
8484 
8485  consdata = SCIPconsGetData(cons);
8486  assert(consdata != NULL);
8487 
8488  nvars = consdata->nvars;
8489 
8490  /* if no activities are associated with this cumulative then this constraint is redundant */
8491  if( nvars == 0 )
8492  return SCIP_OKAY;
8493 
8494  assert(consdata->vars != NULL);
8495 
8496  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8497  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8498  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8499  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8500 
8501  SCIPdebugMessage("create sorted event points for cumulative constraint <%s> with %d jobs\n",
8502  SCIPconsGetName(cons), nvars);
8503 
8504  /* create event point arrays */
8505  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8506  starttimes, endtimes, startindices, endindices, FALSE);
8507 
8508  endindex = 0;
8509  freecapacity = consdata->capacity;
8510  hmin = consdata->hmin;
8511  hmax = consdata->hmax;
8512 
8513  /* check each startpoint of a job whether the capacity is kept or not */
8514  for( j = 0; j < nvars; ++j )
8515  {
8516  curtime = starttimes[j];
8517  SCIPdebugMessage("look at %d-th job with start %d\n", j, curtime);
8518 
8519  if( curtime >= hmax )
8520  break;
8521 
8522  /* remove the capacity requirments for all job which start at the curtime */
8523  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8524 
8525  /* add the capacity requirments for all job which end at the curtime */
8526  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8527 
8528  assert(freecapacity <= consdata->capacity);
8529  assert(endindex <= nvars);
8530 
8531  /* endindex - points to the next job which will finish */
8532  /* j - points to the last job that has been released */
8533 
8534  /* if free capacity is smaller than zero, then add rows to the LP */
8535  if( freecapacity < 0 && curtime >= hmin )
8536  {
8537  int nextstarttime;
8538  int t;
8539 
8540  /* step forward until next job is released and see whether capacity constraint is met or not */
8541  if( j < nvars-1 )
8542  nextstarttime = starttimes[j+1];
8543  else
8544  nextstarttime = endtimes[nvars-1];
8545 
8546  nextstarttime = MIN(nextstarttime, hmax);
8547 
8548  /* create capacity restriction row for current event point */
8549  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8550 
8551  /* create for all points in time between the current event point and next start event point a row if the free
8552  * capacity is still smaller than zero */
8553  for( t = curtime+1 ; t < nextstarttime; ++t )
8554  {
8555  /* add the capacity requirments for all job which end at the curtime */
8556  addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8557 
8558  if( freecapacity < 0 )
8559  {
8560  /* add constraint */
8561  SCIPdebugMessage("add capacity constraint at time %d\n", t);
8562 
8563  /* create capacity restriction row */
8564  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8565  }
8566  else
8567  break;
8568  }
8569  }
8570  } /*lint --e{850}*/
8571 
8572  /* free all buffer arrays */
8573  SCIPfreeBufferArray(scip, &endindices);
8574  SCIPfreeBufferArray(scip, &startindices);
8575  SCIPfreeBufferArray(scip, &endtimes);
8576  SCIPfreeBufferArray(scip, &starttimes);
8577 
8578  return SCIP_OKAY;
8579 }
8580 
8581 /** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8582  * capacity is larger than the capacity of the cumulative constraint
8583  * - for each necessary point in time:
8584  *
8585  * sum_j sum_t demand_j * x_{j,t} <= capacity
8586  *
8587  * where x(j,t) is the binary variables of job j at time t
8588  */
8589 static
8591  SCIP* scip, /**< SCIP data structure */
8592  SCIP_CONS* cons, /**< cumulative constraint */
8593  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8594  )
8595 {
8596  SCIP_CONSDATA* consdata;
8597 
8598  consdata = SCIPconsGetData(cons);
8599  assert(consdata != NULL);
8600  assert(consdata->demandrows == NULL);
8601  assert(consdata->ndemandrows == 0);
8602 
8603  /* collect the linking constraints */
8604  if( consdata->linkingconss == NULL )
8605  {
8606  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8607  }
8608 
8609  SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8610 
8611  /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8612  if( cutsasconss )
8613  {
8614  if( SCIPconsIsInitial(cons) )
8615  {
8616  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
8617  }
8618  if( SCIPconsIsSeparated(cons) )
8619  {
8620  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
8621  }
8622  if( SCIPconsIsEnforced(cons) )
8623  {
8624  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
8625  }
8626  }
8627 
8628  return SCIP_OKAY;
8629 }
8630 
8631 /** adds linear relaxation of cumulative constraint to the LP */
8632 static
8634  SCIP* scip, /**< SCIP data structure */
8635  SCIP_CONS* cons, /**< cumulative constraint */
8636  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8637  )
8638 {
8639  SCIP_CONSDATA* consdata;
8640  int r;
8641 
8642  consdata = SCIPconsGetData(cons);
8643  assert(consdata != NULL);
8644 
8645  if( consdata->demandrows == NULL )
8646  {
8647  SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8648  }
8649 
8650  for( r = 0; r < consdata->ndemandrows; ++r )
8651  {
8652  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8653  {
8654  SCIP_Bool infeasible;
8655 
8656  assert(consdata->demandrows[r] != NULL);
8657  SCIP_CALL( SCIPaddCut(scip, NULL, consdata->demandrows[r], FALSE, &infeasible) );
8658  assert( ! infeasible ); /* this function is only called by initlp -> the cut should be feasible */
8659  }
8660  }
8661 
8662  return SCIP_OKAY;
8663 }
8664 
8665 /** checks constraint for violation, and adds it as a cut if possible */
8666 static
8668  SCIP* scip, /**< SCIP data structure */
8669  SCIP_CONS* cons, /**< cumulative constraint to be separated */
8670  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8671  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8672  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8673  )
8674 { /*lint --e{715}*/
8675  SCIP_CONSDATA* consdata;
8676  int ncuts;
8677  int r;
8678 
8679  assert(scip != NULL);
8680  assert(cons != NULL);
8681  assert(separated != NULL);
8682  assert(cutoff != NULL);
8683 
8684  *separated = FALSE;
8685  *cutoff = FALSE;
8686 
8687  consdata = SCIPconsGetData(cons);
8688  assert(consdata != NULL);
8689 
8690  SCIPdebugMessage("separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8691 
8692  if( consdata->demandrows == NULL )
8693  {
8694  SCIP_CALL( createRelaxation(scip, cons, FALSE) );
8695  }
8696 
8697  ncuts = 0;
8698 
8699  /* check each row that is not contained in LP */
8700  for( r = 0; r < consdata->ndemandrows; ++r )
8701  {
8702  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8703  {
8704  SCIP_Real feasibility;
8705 
8706  if( sol != NULL )
8707  feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8708  else
8709  feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8710 
8711  if( SCIPisFeasNegative(scip, feasibility) )
8712  {
8713  SCIP_CALL( SCIPaddCut(scip, sol, consdata->demandrows[r], FALSE, cutoff) );
8714  if ( *cutoff )
8715  {
8716  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8717  return SCIP_OKAY;
8718  }
8719  *separated = TRUE;
8720  ncuts++;
8721  }
8722  }
8723  }
8724 
8725  if( ncuts > 0 )
8726  {
8727  SCIPdebugMessage("cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8728 
8729  /* if successful, reset age of constraint */
8730  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8731  (*separated) = TRUE;
8732  }
8733 
8734  return SCIP_OKAY;
8735 }
8736 
8737 /** checks constraint for violation, and adds it as a cut if possible */
8738 static
8740  SCIP* scip, /**< SCIP data structure */
8741  SCIP_CONS* cons, /**< logic or constraint to be separated */
8742  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8743  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8744  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8745  )
8746 {
8747  SCIP_CONSDATA* consdata;
8748  SCIP_ROW* row;
8749  SCIP_Real minfeasibility;
8750  int r;
8751 
8752  assert(scip != NULL);
8753  assert(cons != NULL);
8754  assert(separated != NULL);
8755  assert(cutoff != NULL);
8756 
8757  *separated = FALSE;
8758  *cutoff = FALSE;
8759 
8760  consdata = SCIPconsGetData(cons);
8761  assert(consdata != NULL);
8762 
8763  SCIPdebugMessage("separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8764 
8765  /* collect the linking constraints */
8766  if( consdata->linkingconss == NULL )
8767  {
8768  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8769  }
8770 
8771  if( !consdata->covercuts )
8772  {
8773  SCIP_CALL( createCoverCuts(scip, cons) );
8774  }
8775 
8776  row = NULL;
8777  minfeasibility = SCIPinfinity(scip);
8778 
8779  /* check each row of small covers that is not contained in LP */
8780  for( r = 0; r < consdata->nscoverrows; ++r )
8781  {
8782  if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8783  {
8784  SCIP_Real feasibility;
8785 
8786  assert(consdata->scoverrows[r] != NULL);
8787  if( sol != NULL )
8788  feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8789  else
8790  feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8791 
8792  if( minfeasibility > feasibility )
8793  {
8794  minfeasibility = feasibility;
8795  row = consdata->scoverrows[r];
8796  }
8797  }
8798  }
8799 
8800  if( SCIPisFeasNegative(scip, minfeasibility) )
8801  {
8802  SCIPdebugMessage("cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8803  SCIPconsGetName(cons), minfeasibility);
8804 
8805  assert(row != NULL);
8806  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, cutoff) );
8807  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8808  if ( *cutoff )
8809  return SCIP_OKAY;
8810  (*separated) = TRUE;
8811  }
8812 
8813  minfeasibility = SCIPinfinity(scip);
8814  row = NULL;
8815 
8816  /* check each row of small covers that is not contained in LP */
8817  for( r = 0; r < consdata->nbcoverrows; ++r )
8818  {
8819  if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8820  {
8821  SCIP_Real feasibility;
8822 
8823  assert(consdata->bcoverrows[r] != NULL);
8824  if( sol != NULL )
8825  feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8826  else
8827  feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8828 
8829  if( minfeasibility > feasibility )
8830  {
8831  minfeasibility = feasibility;
8832  row = consdata->bcoverrows[r];
8833  }
8834  }
8835  }
8836 
8837  if( SCIPisFeasNegative(scip, minfeasibility) )
8838  {
8839  SCIPdebugMessage("cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8840  SCIPconsGetName(cons), minfeasibility);
8841 
8842  assert(row != NULL);
8843  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, cutoff) );
8844  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8845  if ( *cutoff )
8846  return SCIP_OKAY;
8847  (*separated) = TRUE;
8848  }
8849 
8850  return SCIP_OKAY;
8851 }
8852 
8853 /** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
8854 static
8856  SCIP* scip, /**< SCIP data structure */
8857  SCIP_CONS* cons, /**< constraint to be checked */
8858  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8859  int* startindices, /**< permutation with rspect to the start times */
8860  int curtime, /**< current point in time */
8861  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8862  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8863  SCIP_Bool lower /**< shall cuts be created due to lower or upper bounds? */
8864  )
8865 {
8866  SCIP_CONSDATA* consdata;
8867  char name[SCIP_MAXSTRLEN];
8868  SCIP_Bool infeasible;
8869  int lhs; /* left hand side of constraint */
8870 
8871  SCIP_VAR** activevars;
8872  SCIP_ROW* row;
8873 
8874  int v;
8875 
8876  assert(nstarted > nfinished);
8877 
8878  consdata = SCIPconsGetData(cons);
8879  assert(consdata != NULL);
8880  assert(consdata->nvars > 0);
8881 
8882 
8883  SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
8884 
8885  SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
8886 
8887  if( lower )
8888  {
8889  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
8890 
8891  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, (SCIP_Real) lhs, SCIPinfinity(scip),
8892  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8893  }
8894  else
8895  {
8896  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
8897  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real) lhs,
8898  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8899  }
8900 
8901  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8902 
8903  for( v = 0; v < nstarted - nfinished; ++v )
8904  {
8905  SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
8906  }
8907 
8908  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8909  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8910 
8911  SCIP_CALL( SCIPaddCut(scip, sol, row, TRUE, &infeasible) );
8912  assert( ! infeasible );
8913 
8914  SCIP_CALL( SCIPreleaseRow(scip, &row) );
8915 
8916  /* free buffers */
8917  SCIPfreeBufferArrayNull(scip, &activevars);
8918 
8919  return SCIP_OKAY;
8920 }
8921 
8922 /** checks constraint for violation, and adds it as a cut if possible */
8923 static
8925  SCIP* scip, /**< SCIP data structure */
8926  SCIP_CONS* cons, /**< cumulative constraint to be separated */
8927  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8928  SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
8929  SCIP_Bool* separated /**< pointer to store TRUE, if a cut was found */
8930  )
8931 {
8932 
8933  SCIP_CONSDATA* consdata;
8934 
8935  int* starttimes; /* stores when each job is starting */
8936  int* endtimes; /* stores when each job ends */
8937  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8938  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8939 
8940  int nvars; /* number of activities for this constraint */
8941  int freecapacity; /* remaining capacity */
8942  int curtime; /* point in time which we are just checking */
8943  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8944 
8945  int hmin;
8946  int hmax;
8947  int j;
8948 
8949  assert(scip != NULL);
8950  assert(cons != NULL);
8951 
8952  consdata = SCIPconsGetData(cons);
8953  assert(consdata != NULL);
8954 
8955  nvars = consdata->nvars;
8956 
8957  /* if no activities are associated with this cumulative then this constraint is redundant */
8958  if( nvars <= 1 )
8959  return SCIP_OKAY;
8960 
8961  assert(consdata->vars != NULL);
8962 
8963  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8964  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8965  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8966  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8967 
8968  SCIPdebugMessage("create sorted event points for cumulative constraint <%s> with %d jobs\n",
8969  SCIPconsGetName(cons), nvars);
8970 
8971  /* create event point arrays */
8972  createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
8973 
8974  /* now nvars might be smaller than before! */
8975 
8976  endindex = 0;
8977  freecapacity = consdata->capacity;
8978  hmin = consdata->hmin;
8979  hmax = consdata->hmax;
8980 
8981  /* check each startpoint of a job whether the capacity is kept or not */
8982  for( j = 0; j < nvars; ++j )
8983  {
8984  curtime = starttimes[j];
8985 
8986  if( curtime >= hmax )
8987  break;
8988 
8989  /* remove the capacity requirements for all job which start at the curtime */
8990  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8991 
8992  /* add the capacity requirments for all job which end at the curtime */
8993  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8994 
8995  assert(freecapacity <= consdata->capacity);
8996  assert(endindex <= nvars);
8997 
8998  /* endindex - points to the next job which will finish */
8999  /* j - points to the last job that has been released */
9000 
9001  /* if free capacity is smaller than zero, then add rows to the LP */
9002  if( freecapacity < 0 && curtime >= hmin)
9003  {
9004  /* create capacity restriction row for current event point */
9005  SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, sol, startindices, curtime, j+1, endindex, lower) );
9006  *separated = TRUE;
9007  }
9008  } /*lint --e{850}*/
9009 
9010  /* free all buffer arrays */
9011  SCIPfreeBufferArray(scip, &endindices);
9012  SCIPfreeBufferArray(scip, &startindices);
9013  SCIPfreeBufferArray(scip, &endtimes);
9014  SCIPfreeBufferArray(scip, &starttimes);
9015 
9016  return SCIP_OKAY;
9017 }
9018 
9019 /**@} */
9020 
9021 
9022 /**@name Presolving
9023  *
9024  * @{
9025  */
9026 
9027 #ifndef NDEBUG
9028 /** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9029  * correct
9030  */
9031 static
9033  SCIP* scip, /**< SCIP data structure */
9034  SCIP_CONS* cons /**< constraint to be checked */
9035  )
9036 {
9037  SCIP_CONSDATA* consdata;
9038  int capacity;
9039  int nvars;
9040  int j;
9041 
9042  assert(scip != NULL);
9043  assert(cons != NULL);
9044 
9045  consdata = SCIPconsGetData(cons);
9046  assert(consdata != NULL);
9047 
9048  nvars = consdata->nvars;
9049 
9050  /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9051  if( nvars <= 1 )
9052  return TRUE;
9053 
9054  assert(consdata->vars != NULL);
9055  capacity = consdata->capacity;
9056 
9057  /* check each activity: if demand is larger than capacity the problem is infeasible */
9058  for ( j = 0; j < nvars; ++j )
9059  {
9060  if( consdata->demands[j] > capacity )
9061  return FALSE;
9062  }
9063 
9064  return TRUE;
9065 }
9066 #endif
9067 
9068 /** delete constraint if it consists of at most one job
9069  *
9070  * @todo this method needs to be adjusted w.r.t. effective horizon
9071  */
9072 static
9074  SCIP* scip, /**< SCIP data structure */
9075  SCIP_CONS* cons, /**< constraint to propagate */
9076  int* ndelconss, /**< pointer to store the number of deleted constraints */
9077  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9078  )
9079 {
9080  SCIP_CONSDATA* consdata;
9081 
9082  assert(scip != NULL);
9083  assert(cons != NULL);
9084 
9085  consdata = SCIPconsGetData(cons);
9086  assert(consdata != NULL);
9087 
9088  if( consdata->nvars == 0 )
9089  {
9090  SCIPdebugMessage("delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9091 
9092  SCIP_CALL( SCIPdelCons(scip, cons) );
9093  (*ndelconss)++;
9094  }
9095  else if( consdata->nvars == 1 )
9096  {
9097  if( consdata->demands[0] > consdata->capacity )
9098  (*cutoff) = TRUE;
9099  else
9100  {
9101  SCIPdebugMessage("delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9102 
9103  SCIP_CALL( SCIPdelCons(scip, cons) );
9104  (*ndelconss)++;
9105  }
9106  }
9107 
9108  return SCIP_OKAY;
9109 }
9110 
9111 /** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9112  * this is done in the SCIP_DECL_CONSINITPRE() callback
9113  */
9114 static
9116  SCIP* scip, /**< SCIP data structure */
9117  SCIP_CONS* cons /**< constraint to propagate */
9118  )
9119 {
9120  SCIP_CONSDATA* consdata;
9121  SCIP_VAR* var;
9122  int demand;
9123  int duration;
9124  int hmin;
9125  int hmax;
9126  int est;
9127  int lct;
9128  int j;
9129 
9130  assert(scip != NULL);
9131  assert(cons != NULL);
9132 
9133  consdata = SCIPconsGetData(cons);
9134  assert(consdata != NULL);
9135 
9136  hmin = consdata->hmin;
9137  hmax = consdata->hmax;
9138 
9139  SCIPdebugMessage("check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9140  SCIPconsGetName(cons), hmin, hmax);
9141 
9142  for( j = consdata->nvars-1; j >= 0; --j )
9143  {
9144  var = consdata->vars[j];
9145  demand = consdata->demands[j];
9146  duration = consdata->durations[j];
9147 
9148  /* earliest completion time (ect) and latest start time (lst) */
9149  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9150  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9151 
9152  if( demand == 0 || duration == 0 )
9153  {
9154  /* jobs with zero demand or zero duration can be removed */
9155  SCIPdebugMessage(" remove variable <%s> due to zero %s\n",
9156  SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9157 
9158  /* remove variable form constraint */
9159  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9160  }
9161  else if( est >= hmax || lct <= hmin )
9162  {
9163  SCIPdebugMessage(" remove variable <%s>[%d,%d] with duration <%d>\n",
9164  SCIPvarGetName(var), est, lct - duration, duration);
9165 
9166  /* delete variable at the given position */
9167  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9168 
9169  /* for the statistic we count the number of jobs which are irrelevant */
9170  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9171  }
9172  }
9173 
9174  return SCIP_OKAY;
9175 }
9176 
9177 /** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9178 static
9180  SCIP* scip, /**< SCIP data structure */
9181  SCIP_CONSDATA* consdata, /**< constraint data */
9182  int pos, /**< position of job in the consdata */
9183  int* nchgbds, /**< pointer to store the number of changed bounds */
9184  int* naddconss, /**< pointer to store the number of added constraints */
9185  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9186  )
9187 {
9188  SCIP_VAR* var;
9189  SCIP_Bool tightened;
9190  int duration;
9191  int ect;
9192  int lst;
9193 
9194  assert(scip != NULL);
9195 
9196  /* zero energy jobs should be removed already */
9197  assert(consdata->durations[pos] > 0);
9198  assert(consdata->demands[pos] > 0);
9199 
9200  var = consdata->vars[pos];
9201  assert(var != NULL);
9202  duration = consdata->durations[pos];
9203 
9204  /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9205  SCIPdebugMessage(" variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9206  SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9207 
9208  /* earliest completion time (ect) and latest start time (lst) */
9209  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9210  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9211 
9212  /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9213  if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9214  return SCIP_OKAY;
9215 
9216  if( ect > consdata->hmin && lst < consdata->hmax )
9217  {
9218  /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9219  *cutoff = TRUE;
9220  }
9221  else if( lst < consdata->hmax )
9222  {
9223  /* move the latest start time of this job in such a way that it finishes before or at hmin */
9224  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9225  assert(tightened);
9226  assert(!(*cutoff));
9227  (*nchgbds)++;
9228  }
9229  else if( ect > consdata->hmin )
9230  {
9231  /* move the earliest start time of this job in such a way that it starts after or at hmax */
9232  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9233  assert(tightened);
9234  assert(!(*cutoff));
9235  (*nchgbds)++;
9236  }
9237  else
9238  {
9239  /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9240  * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9241  *
9242  * (var <= hmin - duration) /\ (var >= hmax)
9243  */
9244  SCIP_CONS* cons;
9245 
9246  SCIP_VAR* vartuple[2];
9247  SCIP_BOUNDTYPE boundtypetuple[2];
9248  SCIP_Real boundtuple[2];
9249 
9250  char name[SCIP_MAXSTRLEN];
9251  int leftbound;
9252  int rightbound;
9253 
9254  leftbound = consdata->hmin - duration;
9255  rightbound = consdata->hmax;
9256 
9257  /* allocate temporary memory for arrays */
9258  vartuple[0] = var;
9259  vartuple[1] = var;
9260  boundtuple[0] = (SCIP_Real)leftbound;
9261  boundtuple[1] = (SCIP_Real)rightbound;
9262  boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9263  boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9264 
9265  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9266  SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9267 
9268  /* create and add bounddisjunction constraint */
9269  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9270  TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9271 
9272  SCIPdebugPrintCons(scip, cons, NULL);
9273 
9274  /* add and release the new constraint */
9275  SCIP_CALL( SCIPaddCons(scip, cons) );
9276  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9277  (*naddconss)++;
9278  }
9279 
9280  return SCIP_OKAY;
9281 }
9282 
9283 /** try to removed over sizeed jobs (the demand is larger than the capacity) */
9284 static
9286  SCIP* scip, /**< SCIP data structure */
9287  SCIP_CONS* cons, /**< constraint */
9288  int* nchgbds, /**< pointer to store the number of changed bounds */
9289  int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9290  int* naddconss, /**< pointer to store the number of added constraints */
9291  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9292  )
9293 {
9294  SCIP_CONSDATA* consdata;
9295  int capacity;
9296  int j;
9297 
9298  consdata = SCIPconsGetData(cons);
9299  assert(consdata != NULL);
9300 
9301  /* if a cutoff was already detected just return */
9302  if( *cutoff )
9303  return SCIP_OKAY;
9304 
9305  capacity = consdata->capacity;
9306 
9307  for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9308  {
9309  if( consdata->demands[j] > capacity )
9310  {
9311  SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9312 
9313  /* remove variable form constraint */
9314  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9315  (*nchgcoefs)++;
9316  }
9317  }
9318 
9319  SCIPdebugMessage("cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9320 
9321  return SCIP_OKAY;
9322 }
9323 
9324 /** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9325 static
9327  SCIP* scip, /**< SCIP data structure */
9328  SCIP_VAR* var, /**< integer variable to fix */
9329  SCIP_Bool uplock, /**< has thet start time variable a up lock */
9330  int* nfixedvars /**< pointer to store the number fixed variables */
9331  )
9332 {
9333  SCIP_Bool infeasible;
9334  SCIP_Bool tightened;
9335  SCIP_Bool roundable;
9336 
9337  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9338  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9339  */
9340  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9341  return SCIP_OKAY;
9342 
9343  /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9344  * handler is the only one locking that variable up
9345  */
9346  assert(uplock == TRUE || uplock == FALSE);
9347  assert((int)TRUE == 1);
9348  assert((int)FALSE == 0);
9349 
9350  if( SCIPvarGetNLocksUp(var) > (int)(uplock) )
9351  return SCIP_OKAY;
9352 
9353  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9354 
9355  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9356  * (the transformed problem is always a minimization problem)
9357  */
9358  if( !roundable )
9359  return SCIP_OKAY;
9360 
9361  SCIPdebugMessage("try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9363 
9364  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9365  assert(!infeasible);
9366 
9367  if( tightened )
9368  {
9369  SCIPdebugMessage("fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9370  (*nfixedvars)++;
9371  }
9372 
9373  return SCIP_OKAY;
9374 }
9375 
9376 /** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9377 static
9379  SCIP* scip, /**< SCIP data structure */
9380  SCIP_VAR* var, /**< integer variable to fix */
9381  SCIP_Bool downlock, /**< has the variable a down lock */
9382  int* nfixedvars /**< pointer to store the number fixed variables */
9383  )
9384 {
9385  SCIP_Bool infeasible;
9386  SCIP_Bool tightened;
9387  SCIP_Bool roundable;
9388 
9389  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9390  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9391  */
9392  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9393  return SCIP_OKAY;
9394 
9395  /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9396  * handler is the only one locking that variable down
9397  */
9398  assert(downlock == TRUE || downlock == FALSE);
9399  assert((int)TRUE == 1);
9400  assert((int)FALSE == 0);
9401 
9402  if( SCIPvarGetNLocksDown(var) > (int)(downlock) )
9403  return SCIP_OKAY;
9404 
9405  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9406 
9407  /* is it possible, to round variable down w.r.t. objective function? */
9408  if( !roundable )
9409  return SCIP_OKAY;
9410 
9411  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9412  assert(!infeasible);
9413 
9414  if( tightened )
9415  {
9416  SCIPdebugMessage("fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9417  (*nfixedvars)++;
9418  }
9419 
9420  return SCIP_OKAY;
9421 }
9422 
9423 /** normalize cumulative condition */
9424 static
9426  SCIP* scip, /**< SCIP data structure */
9427  int nvars, /**< number of start time variables (activities) */
9428  SCIP_VAR** vars, /**< array of start time variables */
9429  int* durations, /**< array of durations */
9430  int* demands, /**< array of demands */
9431  int* capacity, /**< pointer to store the changed cumulative capacity */
9432  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9433  int* nchgsides /**< pointer to count number of side changes */
9434  )
9435 { /*lint --e{715}*/
9436  SCIP_Longint gcd;
9437  int mindemand1;
9438  int mindemand2;
9439  int v;
9440 
9441  if( *capacity == 1 || nvars <= 1 )
9442  return SCIP_OKAY;
9443 
9444  assert(demands[nvars-1] <= *capacity);
9445  assert(demands[nvars-2] <= *capacity);
9446 
9447  gcd = (SCIP_Longint)demands[nvars-1];
9448  mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9449  mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9450 
9451  for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9452  {
9453  assert(mindemand1 <= mindemand2);
9454  assert(demands[v] <= *capacity);
9455 
9456  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9457 
9458  if( mindemand1 > demands[v] )
9459  {
9460  mindemand2 = mindemand1;
9461  mindemand1 = demands[v];
9462  }
9463  else if( mindemand2 > demands[v] )
9464  mindemand2 = demands[v];
9465  }
9466 
9467  if( mindemand1 + mindemand2 > *capacity )
9468  {
9469  SCIPdebugMessage("update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9470 
9471  for( v = 0; v < nvars; ++v )
9472  demands[v] = 1;
9473 
9474  (*capacity) = 1;
9475 
9476  (*nchgcoefs) += nvars;
9477  (*nchgsides)++;
9478  }
9479  else if( gcd >= 2 )
9480  {
9481  SCIPdebugMessage("cumulative condition: dividing demands by %"SCIP_LONGINT_FORMAT"\n", gcd);
9482 
9483  for( v = 0; v < nvars; ++v )
9484  demands[v] /= gcd;
9485 
9486  (*capacity) /= gcd;
9487 
9488  (*nchgcoefs) += nvars;
9489  (*nchgsides)++;
9490  }
9491 
9492  return SCIP_OKAY;
9493 }
9494 
9495 /** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9496  * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9497  * capacity since in that case none of the jobs can run in parallel
9498  */
9499 static
9501  SCIP* scip, /**< SCIP data structure */
9502  SCIP_CONS* cons, /**< cumulative constraint */
9503  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9504  int* nchgsides /**< pointer to count number of side changes */
9505  )
9506 {
9507  SCIP_CONSDATA* consdata;
9508  int capacity;
9509 
9510  assert(nchgcoefs != NULL);
9511  assert(nchgsides != NULL);
9512  assert(!SCIPconsIsModifiable(cons));
9513 
9514  consdata = SCIPconsGetData(cons);
9515  assert(consdata != NULL);
9516 
9517  if( consdata->normalized )
9518  return SCIP_OKAY;
9519 
9520  capacity = consdata->capacity;
9521 
9522  /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9523 
9524  SCIP_CALL( normalizeCumulativeCondition(scip, consdata->nvars, consdata->vars, consdata->durations,
9525  consdata->demands, &consdata->capacity, nchgcoefs, nchgsides) );
9526 
9527  consdata->normalized = TRUE;
9528 
9529  if( capacity > consdata->capacity )
9530  consdata->varbounds = FALSE;
9531 
9532  return SCIP_OKAY;
9533 }
9534 
9535 /** computes for the given cumulative condition the effective horizon */
9536 static
9538  SCIP* scip, /**< SCIP data structure */
9539  int nvars, /**< number of variables (jobs) */
9540  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9541  int* durations, /**< array containing corresponding durations */
9542  int* demands, /**< array containing corresponding demands */
9543  int capacity, /**< available cumulative capacity */
9544  int* hmin, /**< pointer to store the left bound of the effective horizon */
9545  int* hmax, /**< pointer to store the right bound of the effective horizon */
9546  int* split /**< point were the cumulative condition can be split */
9547  )
9548 {
9549  SCIP_PROFILE* profile;
9550 
9551  /* create empty resource profile with infinity resource capacity */
9552  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9553 
9554  /* create worst case resource profile */
9555  SCIP_CALL( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands) );
9556 
9557  /* print resource profile in if SCIP_DEBUG is defined */
9558  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
9559 
9560  /* computes the first time point where the resource capacity can be violated */
9561  (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9562 
9563  /* computes the first time point where the resource capacity is satisfied for sure */
9564  (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9565 
9566  (*split) = (*hmax);
9567 
9568  if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9569  {
9570  int* timepoints;
9571  int* loads;
9572  int ntimepoints;
9573  int t;
9574 
9575  /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9576  * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9577  * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9578  * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9579  * explain the certain "old" bound changes
9580  */
9581 
9582  /* search for time points */
9583  ntimepoints = SCIPprofileGetNTimepoints(profile);
9584  timepoints = SCIPprofileGetTimepoints(profile);
9585  loads = SCIPprofileGetLoads(profile);
9586 
9587  /* 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 */
9588  for( t = 0; t < ntimepoints; ++t )
9589  {
9590  /* ignore all time points before the effective horizon */
9591  if( timepoints[t] <= *hmin )
9592  continue;
9593 
9594  /* ignore all time points after the effective horizon */
9595  if( timepoints[t] >= *hmax )
9596  break;
9597 
9598  /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9599  * can split the cumulative constraint into two cumulative constraints
9600  */
9601  if( loads[t] <= capacity )
9602  {
9603  (*split) = timepoints[t];
9604  break;
9605  }
9606  }
9607  }
9608 
9609  /* free worst case profile */
9610  SCIPprofileFree(&profile);
9611 
9612  return SCIP_OKAY;
9613 }
9614 
9615 /** creates and adds a cumulative constraint */
9616 static
9618  SCIP* scip, /**< SCIP data structure */
9619  const char* name, /**< name of constraint */
9620  int nvars, /**< number of variables (jobs) */
9621  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9622  int* durations, /**< array containing corresponding durations */
9623  int* demands, /**< array containing corresponding demands */
9624  int capacity, /**< available cumulative capacity */
9625  int hmin, /**< left bound of time axis to be considered (including hmin) */
9626  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9627  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9628  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9629  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9630  * Usually set to TRUE. */
9631  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9632  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9633  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9634  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9635  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9636  * Usually set to TRUE. */
9637  SCIP_Bool local, /**< is constraint only valid locally?
9638  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9639  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9640  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9641  * adds coefficients to this constraint. */
9642  SCIP_Bool dynamic, /**< is constraint subject to aging?
9643  * Usually set to FALSE. Set to TRUE for own cuts which
9644  * are seperated as constraints. */
9645  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9646  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9647  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9648  * if it may be moved to a more global node?
9649  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9650  )
9651 {
9652  SCIP_CONS* cons;
9653 
9654  /* creates cumulative constraint and adds it to problem */
9655  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9656  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9657 
9658  /* adjust the effective time horizon of the new constraint */
9659  SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9660  SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9661 
9662  /* add and release new cumulative constraint */
9663  SCIP_CALL( SCIPaddCons(scip, cons) );
9664  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9665 
9666  return SCIP_OKAY;
9667 }
9668 
9669 /** computes the effective horizon and checks if the constraint can be decompsed */
9670 static
9672  SCIP* scip, /**< SCIP data structure */
9673  SCIP_CONS* cons, /**< cumulative constraint */
9674  int* ndelconss, /**< pointer to store the number of deleted constraints */
9675  int* naddconss, /**< pointer to store the number of added constraints */
9676  int* nchgsides /**< pointer to store the number of changed sides */
9677  )
9678 {
9679  SCIP_CONSDATA* consdata;
9680  int hmin;
9681  int hmax;
9682  int split;
9683 
9684  consdata = SCIPconsGetData(cons);
9685  assert(consdata != NULL);
9686 
9687  if( consdata->nvars <= 1 )
9688  return SCIP_OKAY;
9689 
9690  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9691  consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9692 
9693  /* check if this time point improves the effective horizon */
9694  if( consdata->hmin < hmin )
9695  {
9696  SCIPdebugMessage("cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9697 
9698  consdata->hmin = hmin;
9699  (*nchgsides)++;
9700  }
9701 
9702  /* check if this time point improves the effective horizon */
9703  if( consdata->hmax > hmax )
9704  {
9705  SCIPdebugMessage("cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9706  consdata->hmax = hmax;
9707  (*nchgsides)++;
9708  }
9709 
9710  /* check if the constraint is redundant */
9711  if( consdata->hmax <= consdata->hmin )
9712  {
9713  SCIPdebugMessage("constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9714  SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9715 
9716  SCIP_CALL( SCIPdelCons(scip, cons) );
9717  (*ndelconss)++;
9718  }
9719  else if( consdata->hmin < split && split < consdata->hmax )
9720  {
9721  char name[SCIP_MAXSTRLEN];
9722  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9723 
9724  SCIPdebugMessage("split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9725  SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9726 
9727  assert(split < consdata->hmax);
9728 
9729  /* creates cumulative constraint and adds it to problem */
9730  SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9731  consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9734 
9735  /* adjust the effective time horizon of the constraint */
9736  consdata->hmax = split;
9737 
9738  assert(consdata->hmin < consdata->hmax);
9739 
9740  /* for the statistic we count the number of time we decompose a cumulative constraint */
9742  (*naddconss)++;
9743  }
9744 
9745  return SCIP_OKAY;
9746 }
9747 
9748 
9749 /** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9750  *
9751  * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9752  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9753  *
9754  * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9755  * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9756  * down-lock of the corresponding start time variable can be removed.
9757  *
9758  * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9759  * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9760  * negative, than the job can be dual fixed to its earlier start time (est).
9761  *
9762  * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9763  * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9764  * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9765  *
9766  * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9767  * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9768  * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9769  * form variable domain is dual feasible.
9770  *
9771  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9772  * the cumulative condition; The deletion has to be done later.
9773  */
9774 static
9776  SCIP* scip, /**< SCIP data structure */
9777  int nvars, /**< number of start time variables (activities) */
9778  SCIP_VAR** vars, /**< array of start time variables */
9779  int* durations, /**< array of durations */
9780  int hmin, /**< left bound of time axis to be considered (including hmin) */
9781  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9782  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9783  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9784  SCIP_CONS* cons, /**< underlying constraint, or NULL */
9785  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9786  int* nfixedvars, /**< pointer to store the number of fixed variables */
9787  int* nchgsides, /**< pointer to store the number of changed sides */
9788  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9789  )
9790 {
9791  SCIP_Real* downimpllbs;
9792  SCIP_Real* downimplubs;
9793  SCIP_Real* downproplbs;
9794  SCIP_Real* downpropubs;
9795  SCIP_Real* upimpllbs;
9796  SCIP_Real* upimplubs;
9797  SCIP_Real* upproplbs;
9798  SCIP_Real* uppropubs;
9799 
9800  int firstminect;
9801  int secondminect;
9802  int v;
9803 
9804  /* get temporary memory for storing probing results needed for step (4) and (5) */
9805  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9806  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9807  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9808  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9809  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9810  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9811  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9812  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9813 
9814  assert(scip != NULL);
9815  assert(nvars > 1);
9816  assert(cons != NULL);
9817 
9818  SCIPdebugMessage("check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9819 
9820  firstminect = INT_MAX;
9821  secondminect = INT_MAX;
9822 
9823  /* compute the two smallest earlier completion times; which are needed for step (5) */
9824  for( v = 0; v < nvars; ++v )
9825  {
9826  int ect;
9827 
9828  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9829 
9830  if( ect < firstminect )
9831  {
9832  secondminect = firstminect;
9833  firstminect = ect;
9834  }
9835  else if( ect < secondminect )
9836  secondminect = ect;
9837  }
9838 
9839  /* loop over all jobs and check if one of the 5 reductions can be applied */
9840  for( v = 0; v < nvars; ++v )
9841  {
9842  SCIP_VAR* var;
9843  int duration;
9844 
9845  int alternativelb;
9846  int minect;
9847  int est;
9848  int ect;
9849  int lst;
9850  int lct;
9851 
9852  var = vars[v];
9853  assert(var != NULL);
9854 
9855  duration = durations[v];
9856  assert(duration > 0);
9857 
9858  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
9859  * time (lct)
9860  */
9861  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9862  ect = est + duration;
9863  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9864  lct = lst + duration;
9865 
9866  /* compute the earliest completion time of all remaining jobs */
9867  if( ect == firstminect )
9868  minect = secondminect;
9869  else
9870  minect = firstminect;
9871 
9872  /* compute potential alternative lower bound (step (4) and (5)) */
9873  alternativelb = MAX(hmin+1, minect);
9874  alternativelb = MIN(alternativelb, hmax);
9875 
9876  if( lct <= hmin )
9877  {
9878  /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
9879  * cumulative condition
9880  */
9881  SCIPdebugMessage(" variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
9882  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
9883 
9884  /* mark variable to be irrelevant */
9885  irrelevants[v] = TRUE;
9886 
9887  /* for the statistic we count the number of jobs which are irrelevant */
9888  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9889  }
9890  else if( lst <= hmin && SCIPconsIsChecked(cons) )
9891  {
9892  /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
9893  * so the down lock can be omitted
9894  */
9895 
9896  assert(downlocks != NULL);
9897  assert(uplocks != NULL);
9898 
9899  if( !uplocks[v] )
9900  {
9901  /* the variables has no up lock and we can also remove the down lock;
9902  * => lst <= hmin and ect >= hmax
9903  * => remove job and reduce capacity by the demand of that job
9904  *
9905  * We mark the job to be deletable. The removement together with the capacity reducion is done later
9906  */
9907 
9908  SCIPdebugMessage(" variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
9909  SCIPvarGetName(var), ect - duration, lst, duration);
9910 
9911  /* mark variable to be irrelevant */
9912  irrelevants[v] = TRUE;
9913 
9914  /* for the statistic we count the number of jobs which always run during the effective horizon */
9916  }
9917 
9918  if( downlocks[v] )
9919  {
9920  SCIPdebugMessage(" remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
9921  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
9922 
9923  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
9924  downlocks[v] = FALSE;
9925  (*nchgsides)++;
9926 
9927  /* for the statistic we count the number of removed locks */
9929  }
9930  }
9931  else if( ect <= hmin )
9932  {
9933  /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
9934  * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
9935  * removed form the cumulative condition after it was fixed to its earliest start time
9936  */
9937 
9938  /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
9939  * bound;
9940  */
9941  if( downlocks != NULL && SCIPconsIsChecked(cons) )
9942  {
9943  /* fix integer start time variable if possible to it lower bound */
9944  SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
9945  }
9946 
9947  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
9948  {
9949  SCIPdebugMessage(" variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
9950  SCIPvarGetName(var), ect - duration, lst, duration);
9951 
9952  /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
9953  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
9954 
9955  /* mark variable to be irrelevant */
9956  irrelevants[v] = TRUE;
9957 
9958  /* for the statistic we count the number of jobs which are dual fixed */
9960  }
9961  }
9962  else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
9963  {
9964  assert(downlocks != NULL);
9965 
9966  /* check step (4) and (5) */
9967 
9968  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
9969  * is in favor of rounding the variable down
9970  */
9971  if( SCIPvarGetNLocksDown(var) == (int)(downlocks[v]) )
9972  {
9973  SCIP_Bool roundable;
9974 
9975  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9976 
9977  if( roundable )
9978  {
9979  if( alternativelb > lst )
9980  {
9981  SCIP_Bool infeasible;
9982  SCIP_Bool fixed;
9983 
9984  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
9985  assert(!infeasible);
9986  assert(fixed);
9987 
9988  (*nfixedvars)++;
9989 
9990  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
9991  * constraints
9992  */
9994  }
9995  else
9996  {
9997  SCIP_Bool success;
9998 
9999  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10000  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10001  * infeasible we can apply the dual reduction; otherwise we do nothing
10002  */
10003  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10004  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10005  nfixedvars, &success, cutoff) );
10006 
10007  if( success )
10008  {
10010  }
10011  }
10012  }
10013  }
10014  }
10015 
10016  SCIPdebugMessage("********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10017  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10018  }
10019 
10020  /* free temporary memory */
10021  SCIPfreeBufferArray(scip, &uppropubs);
10022  SCIPfreeBufferArray(scip, &upproplbs);
10023  SCIPfreeBufferArray(scip, &upimplubs);
10024  SCIPfreeBufferArray(scip, &upimpllbs);
10025  SCIPfreeBufferArray(scip, &downpropubs);
10026  SCIPfreeBufferArray(scip, &downproplbs);
10027  SCIPfreeBufferArray(scip, &downimplubs);
10028  SCIPfreeBufferArray(scip, &downimpllbs);
10029 
10030  return SCIP_OKAY;
10031 }
10032 
10033 /** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10034  *
10035  * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10036  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10037  *
10038  * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10039  * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10040  * up-lock of the corresponding start time variable can be removed.
10041  *
10042  * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10043  * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10044  * positive, than the job can be dual fixed to its latest start time (lst).
10045  *
10046  * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10047  * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10048  * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10049  * of the corresponding job).
10050 
10051  * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10052  * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10053  * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10054  * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10055  *
10056  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10057  * the cumulative condition; The deletion has to be done later.
10058  */
10059 static
10061  SCIP* scip, /**< SCIP data structure */
10062  int nvars, /**< number of start time variables (activities) */
10063  SCIP_VAR** vars, /**< array of start time variables */
10064  int* durations, /**< array of durations */
10065  int hmin, /**< left bound of time axis to be considered (including hmin) */
10066  int hmax, /**< right bound of time axis to be considered (not including hmax) */
10067  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10068  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10069  SCIP_CONS* cons, /**< underlying constraint, or NULL */
10070  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10071  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10072  int* nchgsides, /**< pointer to store the number of changed sides */
10073  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10074  )
10075 {
10076  SCIP_Real* downimpllbs;
10077  SCIP_Real* downimplubs;
10078  SCIP_Real* downproplbs;
10079  SCIP_Real* downpropubs;
10080  SCIP_Real* upimpllbs;
10081  SCIP_Real* upimplubs;
10082  SCIP_Real* upproplbs;
10083  SCIP_Real* uppropubs;
10084 
10085  int firstmaxlst;
10086  int secondmaxlst;
10087  int v;
10088 
10089  /* get temporary memory for storing probing results needed for step (4) and (5) */
10090  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10091  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10092  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10093  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10094  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10095  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10096  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10097  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10098 
10099  assert(scip != NULL);
10100  assert(nvars > 1);
10101  assert(cons != NULL);
10102 
10103  SCIPdebugMessage("check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10104 
10105  firstmaxlst = INT_MIN;
10106  secondmaxlst = INT_MIN;
10107 
10108  /* compute the two largest latest start times; which are needed for step (5) */
10109  for( v = 0; v < nvars; ++v )
10110  {
10111  int lst;
10112 
10113  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(vars[v]));
10114 
10115  if( lst > firstmaxlst )
10116  {
10117  secondmaxlst = firstmaxlst;
10118  firstmaxlst = lst;
10119  }
10120  else if( lst > secondmaxlst )
10121  secondmaxlst = lst;
10122  }
10123 
10124  /* loop over all jobs and check if one of the 5 reductions can be applied */
10125  for( v = 0; v < nvars; ++v )
10126  {
10127  SCIP_VAR* var;
10128  int duration;
10129 
10130  int alternativeub;
10131  int maxlst;
10132  int est;
10133  int ect;
10134  int lst;
10135 
10136  var = vars[v];
10137  assert(var != NULL);
10138 
10139  duration = durations[v];
10140  assert(duration > 0);
10141 
10142  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10143  * time (lct)
10144  */
10145  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10146  ect = est + duration;
10147  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10148 
10149  /* compute the latest start time of all remaining jobs */
10150  if( lst == firstmaxlst )
10151  maxlst = secondmaxlst;
10152  else
10153  maxlst = firstmaxlst;
10154 
10155  /* compute potential alternative upper bound (step (4) and (5)) */
10156  alternativeub = MIN(hmax - 1, maxlst) - duration;
10157  alternativeub = MAX(alternativeub, hmin);
10158 
10159  if( est >= hmax )
10160  {
10161  /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10162  * cumulative condition
10163  */
10164  SCIPdebugMessage(" variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10165  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10166 
10167  /* mark variable to be irrelevant */
10168  irrelevants[v] = TRUE;
10169 
10170  /* for the statistic we count the number of jobs which are irrelevant */
10171  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10172  }
10173  else if( ect >= hmax && SCIPconsIsChecked(cons) )
10174  {
10175  assert(downlocks != NULL);
10176  assert(uplocks != NULL);
10177 
10178  /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10179  * so the up lock can be omitted
10180  */
10181 
10182  if( !downlocks[v] )
10183  {
10184  /* the variables has no down lock and we can also remove the up lock;
10185  * => lst <= hmin and ect >= hmax
10186  * => remove job and reduce capacity by the demand of that job
10187  */
10188  SCIPdebugMessage(" variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10189  SCIPvarGetName(var), est, lst, duration);
10190 
10191  /* mark variable to be irrelevant */
10192  irrelevants[v] = TRUE;
10193 
10194  /* for the statistic we count the number of jobs which always run during the effective horizon */
10196  }
10197 
10198  if( uplocks[v] )
10199  {
10200  SCIPdebugMessage(" remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10201  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10202 
10203  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10204  uplocks[v] = FALSE;
10205  (*nchgsides)++;
10206 
10207  /* for the statistic we count the number of removed locks */
10209  }
10210  }
10211  else if( lst >= hmax )
10212  {
10213  /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10214  * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10215  * removed form the cumulative condition after it was fixed to its latest start time
10216  */
10217 
10218  /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10219  * bound
10220  */
10221  if( uplocks != NULL && SCIPconsIsChecked(cons) )
10222  {
10223  /* fix integer start time variable if possible to its upper bound */
10224  SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10225  }
10226 
10227  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10228  {
10229  SCIPdebugMessage(" variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10230  SCIPvarGetName(var), est, lst, duration);
10231 
10232  /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10233  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10234 
10235  /* mark variable to be irrelevant */
10236  irrelevants[v] = TRUE;
10237 
10238  /* for the statistic we count the number of jobs which are dual fixed */
10240  }
10241  }
10242  else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10243  {
10244  assert(uplocks != NULL);
10245 
10246  /* check step (4) and (5) */
10247 
10248  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10249  * is in favor of rounding the variable down
10250  */
10251  if( SCIPvarGetNLocksUp(var) == (int)(uplocks[v]) )
10252  {
10253  SCIP_Bool roundable;
10254 
10255  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10256 
10257  if( roundable )
10258  {
10259  if( alternativeub < est )
10260  {
10261  SCIP_Bool infeasible;
10262  SCIP_Bool fixed;
10263 
10264  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10265  assert(!infeasible);
10266  assert(fixed);
10267 
10268  (*nfixedvars)++;
10269 
10270  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10271  * constraints
10272  */
10274  }
10275  else
10276  {
10277  SCIP_Bool success;
10278 
10279  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10280  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10281  * in infeasible we can apply the dual reduction; otherwise we do nothing
10282  */
10283  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10284  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10285  nfixedvars, &success, cutoff) );
10286 
10287  if( success )
10288  {
10290  }
10291  }
10292  }
10293  }
10294  }
10295  }
10296 
10297  /* free temporary memory */
10298  SCIPfreeBufferArray(scip, &uppropubs);
10299  SCIPfreeBufferArray(scip, &upproplbs);
10300  SCIPfreeBufferArray(scip, &upimplubs);
10301  SCIPfreeBufferArray(scip, &upimpllbs);
10302  SCIPfreeBufferArray(scip, &downpropubs);
10303  SCIPfreeBufferArray(scip, &downproplbs);
10304  SCIPfreeBufferArray(scip, &downimplubs);
10305  SCIPfreeBufferArray(scip, &downimpllbs);
10306 
10307  return SCIP_OKAY;
10308 }
10309 
10310 /** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10311 static
10313  SCIP* scip, /**< SCIP data structure */
10314  SCIP_CONS* cons, /**< cumulative constraint */
10315  int* nfixedvars, /**< pointer to store the number of fixed variables */
10316  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10317  int* nchgsides, /**< pointer to store the number of changed sides */
10318  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10319  )
10320 {
10321  SCIP_CONSDATA* consdata;
10322  SCIP_Bool* irrelevants;
10323  int nvars;
10324  int v;
10325 
10326  assert(scip != NULL);
10327  assert(cons != NULL);
10328  assert(!(*cutoff));
10329 
10330  consdata = SCIPconsGetData(cons);
10331  assert(consdata != NULL);
10332 
10333  nvars = consdata->nvars;
10334 
10335  if( nvars <= 1 )
10336  return SCIP_OKAY;
10337 
10338  SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10339  BMSclearMemoryArray(irrelevants, nvars);
10340 
10341  /* presolve constraint form the earlier start time point of view */
10342  SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10343  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10344  irrelevants, nfixedvars, nchgsides, cutoff) );
10345 
10346  /* presolve constraint form the latest completion time point of view */
10347  SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10348  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10349  irrelevants, nfixedvars, nchgsides, cutoff) );
10350 
10351  /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10352  * order to ensure a correct behaviour
10353  */
10354  for( v = nvars-1; v >= 0; --v )
10355  {
10356  if( irrelevants[v] )
10357  {
10358  SCIP_VAR* var;
10359  int ect;
10360  int lst;
10361 
10362  var = consdata->vars[v];
10363  assert(var != NULL);
10364 
10365  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10366  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10367 
10368  /* check if the jobs runs completely during the effective horizon */
10369  if( lst <= consdata->hmin && ect >= consdata->hmax )
10370  {
10371  if( consdata->capacity < consdata->demands[v] )
10372  {
10373  *cutoff = TRUE;
10374  break;
10375  }
10376 
10377  consdata->capacity -= consdata->demands[v];
10378  consdata->varbounds = FALSE;
10379  }
10380 
10381  SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10382  (*nchgcoefs)++;
10383  }
10384  }
10385 
10386  SCIPfreeBufferArray(scip, &irrelevants);
10387 
10388  return SCIP_OKAY;
10389 }
10390 
10391 /** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10392 static
10394  SCIP* scip, /**< SCIP data structure */
10395  SCIP_CONSDATA* consdata, /**< constraint data */
10396  int* startindices, /**< permutation with rspect to the start times */
10397  int curtime, /**< current point in time */
10398  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10399  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10400  SCIP_Longint** demands, /**< pointer to array storing the demands */
10401  int* ndemands /**< pointer to store the number of different demands */
10402  )
10403 {
10404  int startindex;
10405  int ncountedvars;
10406 
10407  assert(demands != NULL);
10408  assert(ndemands != NULL);
10409 
10410  ncountedvars = 0;
10411  startindex = nstarted - 1;
10412 
10413  *ndemands = 0;
10414 
10415  /* search for the (nstarted - nfinished) jobs which are active at curtime */
10416  while( nstarted - nfinished > ncountedvars )
10417  {
10418  SCIP_VAR* var;
10419  int endtime;
10420  int varidx;
10421 
10422  /* collect job information */
10423  varidx = startindices[startindex];
10424  assert(varidx >= 0 && varidx < consdata->nvars);
10425 
10426  var = consdata->vars[varidx];
10427  assert(var != NULL);
10428 
10429  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10430 
10431  /* check the end time of this job is larger than the curtime; in this case the job is still running */
10432  if( endtime > curtime )
10433  {
10434  if( consdata->demands[varidx] < consdata->capacity )
10435  {
10436  (*demands)[*ndemands] = consdata->demands[varidx];
10437  (*ndemands)++;
10438  }
10439  ncountedvars++;
10440  }
10441 
10442  startindex--;
10443  }
10444 
10445  return SCIP_OKAY;
10446 }
10447 
10448 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10449  * constraint
10450  */
10451 static
10453  SCIP* scip, /**< SCIP data structure */
10454  SCIP_CONS* cons, /**< constraint to be checked */
10455  int* startindices, /**< permutation with rspect to the start times */
10456  int curtime, /**< current point in time */
10457  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10458  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10459  int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10460  )
10461 {
10462  SCIP_CONSDATA* consdata;
10463  SCIP_Longint* demands;
10464  SCIP_Real* profits;
10465  int* items;
10466  int ndemands;
10467  SCIP_Bool success;
10468  SCIP_Real solval;
10469  int j;
10470  assert(nstarted > nfinished);
10471 
10472  consdata = SCIPconsGetData(cons);
10473  assert(consdata != NULL);
10474  assert(consdata->nvars > 0);
10475  assert(consdata->capacity > 0);
10476 
10477  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10478  ndemands = 0;
10479 
10480  /* get demand array to initialize knapsack problem */
10481  SCIP_CALL( collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands) );
10482 
10483  /* create array for profits */
10484  SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10485  SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10486  for( j = 0; j < ndemands; ++j )
10487  {
10488  profits[j] = (SCIP_Real) demands[j];
10489  items[j] = j;/* this is only a dummy value*/
10490  }
10491 
10492  /* solve knapsack problem and get maximum capacity usage <= capacity */
10493  SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10494  items, NULL, NULL, NULL, NULL, &solval, &success) );
10495 
10496  assert(SCIPisFeasIntegral(scip, solval));
10497 
10498  /* store result */
10499  *bestcapacity = SCIPconvertRealToInt(scip, solval);
10500 
10501  SCIPfreeBufferArray(scip, &items);
10502  SCIPfreeBufferArray(scip, &profits);
10503  SCIPfreeBufferArray(scip, &demands);
10504 
10505  return SCIP_OKAY;
10506 }
10507 
10508 /** try to tighten the capacity
10509  * -- using DP for knapsack, we find the maximum possible capacity usage
10510  * -- neglects hmin and hmax, such that it is also able to check solutions globally
10511  */
10512 static
10514  SCIP* scip, /**< SCIP data structure */
10515  SCIP_CONS* cons, /**< cumulative constraint */
10516  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10517  int* nchgsides /**< pointer to store the number of changed sides */
10518  )
10519 {
10520  SCIP_CONSDATA* consdata;
10521  int* starttimes; /* stores when each job is starting */
10522  int* endtimes; /* stores when each job ends */
10523  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10524  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10525 
10526  int nvars; /* number of activities for this constraint */
10527  int freecapacity; /* remaining capacity */
10528  int curtime; /* point in time which we are just checking */
10529  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10530 
10531  int bestcapacity;
10532 
10533  int j;
10534 
10535  assert(scip != NULL);
10536  assert(cons != NULL);
10537  assert(nchgsides != NULL);
10538 
10539  consdata = SCIPconsGetData(cons);
10540  assert(consdata != NULL);
10541 
10542  nvars = consdata->nvars;
10543 
10544  /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10545  if( nvars <= 1 || consdata->capacity <= 1 )
10546  return SCIP_OKAY;
10547 
10548  assert(consdata->vars != NULL);
10549 
10550  SCIPdebugMessage("try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10551  SCIPconsGetName(cons), consdata->capacity);
10552 
10553  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10554  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10555  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10556  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10557 
10558  /* create event point arrays */
10559  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10560  starttimes, endtimes, startindices, endindices, FALSE);
10561 
10562  bestcapacity = 1;
10563  endindex = 0;
10564  freecapacity = consdata->capacity;
10565 
10566  /* check each startpoint of a job whether the capacity is kept or not */
10567  for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10568  {
10569  curtime = starttimes[j];
10570  SCIPdebugMessage("look at %d-th job with start %d\n", j, curtime);
10571 
10572  /* remove the capacity requirments for all job which start at the curtime */
10573  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10574 
10575  /* add the capacity requirments for all job which end at the curtime */
10576  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10577 
10578  assert(freecapacity <= consdata->capacity);
10579  assert(endindex <= nvars);
10580 
10581  /* endindex - points to the next job which will finish */
10582  /* j - points to the last job that has been released */
10583 
10584  /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10585  if( freecapacity < 0 )
10586  {
10587  int newcapacity;
10588 
10589  newcapacity = 1;
10590 
10591  /* get best possible upper bound on capacity usage */
10592  SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10593 
10594  /* update bestcapacity */
10595  bestcapacity = MAX(bestcapacity, newcapacity);
10596  SCIPdebugMessage("after highest cap usage: bestcapacity = %d\n", bestcapacity);
10597  }
10598 
10599  /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10600  if( freecapacity > 0 && freecapacity != consdata->capacity )
10601  {
10602  bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10603  SCIPdebugMessage("after peak < cap: bestcapacity = %d\n", bestcapacity);
10604  }
10605 
10606  /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10607  if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10608  {
10609  /* if demands[startindices[j]] == cap then exactly that job is running */
10610  SCIPdebugMessage("--> cannot decrease capacity since sum equals capacity\n");
10611  bestcapacity = consdata->capacity;
10612  break;
10613  }
10614  } /*lint --e{850}*/
10615 
10616  /* free all buffer arrays */
10617  SCIPfreeBufferArray(scip, &endindices);
10618  SCIPfreeBufferArray(scip, &startindices);
10619  SCIPfreeBufferArray(scip, &endtimes);
10620  SCIPfreeBufferArray(scip, &starttimes);
10621 
10622  /* check whether capacity can be tightened and whether demands need to be adjusted */
10623  if( bestcapacity < consdata->capacity )
10624  {
10625  int oldnchgcoefs;
10626 
10627  oldnchgcoefs = *nchgcoefs;
10628 
10629  SCIPdebugMessage("+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10630  SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10631 
10632  for( j = 0; j < nvars; ++j )
10633  {
10634  if( consdata->demands[j] == consdata->capacity )
10635  {
10636  consdata->demands[j] = bestcapacity;
10637  (*nchgcoefs)++;
10638  }
10639  }
10640 
10641  consdata->capacity = bestcapacity;
10642  (*nchgsides)++;
10643 
10644  SCIPdebugPrintf("; changed additionally %d coefficients\n", (*nchgcoefs)-oldnchgcoefs);
10645 
10646  consdata->varbounds = FALSE;
10647  }
10648 
10649  return SCIP_OKAY;
10650 }
10651 
10652 /** tries to change coefficients:
10653  * demand_j < cap && all other parallel jobs in conflict
10654  * ==> set demand_j := cap
10655  */
10656 static
10658  SCIP* scip, /**< SCIP data structure */
10659  SCIP_CONS* cons, /**< cumulative constraint */
10660  int* nchgcoefs /**< pointer to count total number of changed coefficients */
10661  )
10662 {
10663  SCIP_CONSDATA* consdata;
10664  int nvars;
10665  int j;
10666  int oldnchgcoefs;
10667  int mindemand;
10668 
10669  assert(scip != NULL);
10670  assert(cons != NULL);
10671  assert(nchgcoefs != NULL);
10672 
10673  /* get constraint data for some parameter testings only! */
10674  consdata = SCIPconsGetData(cons);
10675  assert(consdata != NULL);
10676 
10677  nvars = consdata->nvars;
10678  oldnchgcoefs = *nchgcoefs;
10679 
10680  if( nvars <= 0 )
10681  return SCIP_OKAY;
10682 
10683  /* PRE1:
10684  * check all jobs j whether: r_j + r_min > capacity holds
10685  * if so: adjust r_j to capacity
10686  */
10687  mindemand = consdata->demands[0];
10688  for( j = 0; j < nvars; ++j )
10689  {
10690  mindemand = MIN(mindemand, consdata->demands[j]);
10691  }
10692 
10693  /*check each job */
10694  for( j = 0; j < nvars; ++j )
10695  {
10696  if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10697  {
10698  SCIPdebugMessage("+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10699  consdata->demands[j], consdata->capacity);
10700  consdata->demands[j] = consdata->capacity;
10701  (*nchgcoefs)++;
10702  }
10703  }
10704 
10705  /* PRE2:
10706  * check for each job (with d_j < cap)
10707  * whether it is disjunctive to all others over the time horizon
10708  */
10709  for( j = 0; j < nvars; ++j )
10710  {
10711  SCIP_Bool chgcoef;
10712  int est_j;
10713  int lct_j;
10714  int i;
10715 
10716  assert(consdata->demands[j] <= consdata->capacity);
10717 
10718  if( consdata->demands[j] == consdata->capacity )
10719  continue;
10720 
10721  chgcoef = TRUE;
10722 
10723  est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10724  lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10725 
10726  for( i = 0; i < nvars; ++i )
10727  {
10728  int est_i;
10729  int lct_i;
10730 
10731  if( i == j )
10732  continue;
10733 
10734  est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10735  lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10736 
10737  if( est_i >= lct_j || est_j >= lct_i )
10738  continue;
10739 
10740  if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10741  {
10742  chgcoef = FALSE;
10743  break;
10744  }
10745  }
10746 
10747  if( chgcoef )
10748  {
10749  SCIPdebugMessage("+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10750  consdata->demands[j], consdata->capacity);
10751  consdata->demands[j] = consdata->capacity;
10752  (*nchgcoefs)++;
10753  }
10754 
10755  }
10756 
10757  if( (*nchgcoefs) > oldnchgcoefs )
10758  {
10759  SCIPdebugMessage("+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10760  (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10761  }
10762 
10763  return SCIP_OKAY;
10764 }
10765 
10766 #if 0
10767 /** try to reformulate constraint by replacing certain jobs */
10768 static
10769 SCIP_RETCODE reformulateCons(
10770  SCIP* scip, /**< SCIP data structure */
10771  SCIP_CONS* cons, /**< cumulative constraint */
10772  int* naggrvars /**< pointer to store the number of aggregated variables */
10773  )
10774 {
10775  SCIP_CONSDATA* consdata;
10776  int hmin;
10777  int hmax;
10778  int nvars;
10779  int v;
10780 
10781  consdata = SCIPconsGetData(cons);
10782  assert(cons != NULL);
10783 
10784  nvars = consdata->nvars;
10785  assert(nvars > 1);
10786 
10787  hmin = consdata->hmin;
10788  hmax = consdata->hmax;
10789  assert(hmin < hmax);
10790 
10791  for( v = 0; v < nvars; ++v )
10792  {
10793  SCIP_VAR* var;
10794  int duration;
10795  int est;
10796  int ect;
10797  int lst;
10798  int lct;
10799 
10800  var = consdata->vars[v];
10801  assert(var != NULL);
10802 
10803  duration = consdata->durations[v];
10804 
10805  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10806  ect = est + duration;
10807  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10808  lct = lst + duration;
10809 
10810  /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10811  assert(lst > hmin || ect < hmax);
10812 
10813  if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10814  {
10815  SCIP_VAR* aggrvar;
10816  char name[SCIP_MAXSTRLEN];
10817  SCIP_Bool infeasible;
10818  SCIP_Bool redundant;
10819  SCIP_Bool aggregated;
10820  int shift;
10821 
10822  shift = est - (hmin - lct + MIN(hmin, ect));
10823  assert(shift > 0);
10824  lst = hmin;
10825  duration = hmin - lct;
10826 
10827  SCIPdebugMessage("replace variable <%s>[%g,%g] by [%d,%d]\n",
10828  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10829 
10830  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10831  SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10833  SCIP_CALL( SCIPaddVar(scip, var) );
10834  SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10835 
10836  assert(!infeasible);
10837  assert(!redundant);
10838  assert(aggregated);
10839 
10840  /* replace variable */
10841  consdata->durations[v] = duration;
10842  consdata->vars[v] = aggrvar;
10843 
10844  /* remove and add locks */
10845  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10846  SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10847 
10848  SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10849 
10850  (*naggrvars)++;
10851  }
10852  }
10853 
10854  return SCIP_OKAY;
10855 }
10856 #endif
10857 
10858 /** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10859 static
10861  SCIP* scip, /**< SCIP data structure */
10862  SCIP_CONS* cons, /**< cumulative constraint */
10863  int* naddconss /**< pointer to store the number of added constraints */
10864  )
10865 {
10866  SCIP_CONSDATA* consdata;
10867  SCIP_VAR** vars;
10868  int* durations;
10869  int* demands;
10870  int capacity;
10871  int halfcapacity;
10872  int mindemand;
10873  int nvars;
10874  int v;
10875 
10876  consdata = SCIPconsGetData(cons);
10877  assert(consdata != NULL);
10878 
10879  capacity = consdata->capacity;
10880 
10881  if( capacity == 1 )
10882  return SCIP_OKAY;
10883 
10884  SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
10885  SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
10886  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10887 
10888  halfcapacity = capacity / 2;
10889  mindemand = consdata->capacity;
10890  nvars = 0;
10891 
10892  /* collect all jobs with demand larger than half of the capacity */
10893  for( v = 0; v < consdata->nvars; ++v )
10894  {
10895  if( consdata->demands[v] > halfcapacity )
10896  {
10897  vars[nvars] = consdata->vars[v];
10898  demands[nvars] = 1;
10899  durations[nvars] = consdata->durations[v];
10900  nvars++;
10901 
10902  mindemand = MIN(mindemand, consdata->demands[v]);
10903  }
10904  }
10905 
10906  if( nvars > 0 )
10907  {
10908  /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
10909  * job is still to large to be scheduled in parallel
10910  */
10911  for( v = 0; v < consdata->nvars; ++v )
10912  {
10913  if( consdata->demands[v] > halfcapacity )
10914  continue;
10915 
10916  if( mindemand + consdata->demands[v] > capacity )
10917  {
10918  demands[nvars] = 1;
10919  durations[nvars] = consdata->durations[v];
10920  vars[nvars] = consdata->vars[v];
10921  nvars++;
10922 
10923  /* adjust minimum demand of collected jobs */
10924  mindemand = MIN(mindemand, consdata->demands[v]);
10925  }
10926  }
10927 
10928  /* creates cumulative constraint and adds it to problem */
10929  SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
10931  (*naddconss)++;
10932  }
10933 
10934  SCIPfreeBufferArray(scip, &demands);
10935  SCIPfreeBufferArray(scip, &durations);
10936  SCIPfreeBufferArray(scip, &vars);
10937 
10938  return SCIP_OKAY;
10939 }
10940 
10941 /** presolve given constraint */
10942 static
10944  SCIP* scip, /**< SCIP data structure */
10945  SCIP_CONS* cons, /**< cumulative constraint */
10946  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
10947  int* nfixedvars, /**< pointer to store the number of fixed variables */
10948 #if 0
10949  int* naggrvars, /**< pointer to counter which is increased by the number of deduced variable aggregations */
10950 #endif
10951  int* nchgbds, /**< pointer to store the number of changed bounds */
10952  int* ndelconss, /**< pointer to store the number of deleted constraints */
10953  int* naddconss, /**< pointer to store the number of added constraints */
10954  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10955  int* nchgsides, /**< pointer to store the number of changed sides */
10956  SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
10957  SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
10958  )
10959 {
10960  assert(!SCIPconsIsDeleted(cons));
10961 
10962  /* only perform dual reductions on model constraints */
10963  if( conshdlrdata->dualpresolve )
10964  {
10965  /* computes the effective horizon and checks if the constraint can be decomposed */
10966  SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
10967 
10968  if( SCIPconsIsDeleted(cons) )
10969  return SCIP_OKAY;
10970 
10971  /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
10972  * fixings (dual reductions)
10973  */
10974  SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
10975 
10976  if( *cutoff || *unbounded )
10977  return SCIP_OKAY;
10978 
10979  SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
10980 
10981  if( *cutoff || SCIPconsIsDeleted(cons) )
10982  return SCIP_OKAY;
10983  }
10984 
10985  /* remove jobs which have a demand larger than the capacity */
10986  SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
10987  assert((*cutoff) || checkDemands(scip, cons));
10988 
10989  if( *cutoff )
10990  return SCIP_OKAY;
10991 
10992  if( conshdlrdata->normalize )
10993  {
10994  /* divide demands by their greatest common divisor */
10995  SCIP_CALL( normalizeDemands(scip, cons, nchgcoefs, nchgsides) );
10996  }
10997 
10998  /* delete constraint with one job */
10999  SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11000 
11001  if( *cutoff || SCIPconsIsDeleted(cons) )
11002  return SCIP_OKAY;
11003 
11004  if( conshdlrdata->coeftightening )
11005  {
11006  /* try to tighten the capacity */
11007  SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11008 
11009  /* try to tighten the coefficients */
11010  SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11011  }
11012 
11013  assert(checkDemands(scip, cons) || *cutoff);
11014 
11015 #if 0
11016  SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11017 #endif
11018 
11019  return SCIP_OKAY;
11020 }
11021 
11022 /**@name TClique Graph callbacks
11023  *
11024  * @{
11025  */
11026 
11027 /** tclique graph data */
11028 struct TCLIQUE_Graph
11029 {
11030  SCIP_VAR** vars; /**< start time variables each of them is a node */
11031  SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11032  SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11033  SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11034  TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11035  int* ninarcs; /**< number if in arcs for the precedence graph */
11036  int* noutarcs; /**< number if out arcs for the precedence graph */
11037  int* durations; /**< for each node the duration of the corresponding job */
11038  int nnodes; /**< number of nodes */
11039  int size; /**< size of the array */
11040 };
11041 
11042 /** gets number of nodes in the graph */
11043 static
11044 TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11046  assert(tcliquegraph != NULL);
11047 
11048  return tcliquegraph->nnodes;
11049 }
11050 
11051 /** gets weight of nodes in the graph */
11052 static
11053 TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11055  assert(tcliquegraph != NULL);
11056 
11057  return tcliquegraph->weights;
11058 }
11059 
11060 /** returns, whether the edge (node1, node2) is in the graph */
11061 static
11062 TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11064  assert(tcliquegraph != NULL);
11065  assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11066  assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11067 
11068  /* check if an arc exits in the precedence graph */
11069  if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11070  return TRUE;
11071 
11072  /* check if an edge exits in the non-overlapping graph */
11073  if( tcliquegraph->demandmatrix[node1][node2] )
11074  return TRUE;
11075 
11076  return FALSE;
11077 }
11078 
11079 /** selects all nodes from a given set of nodes which are adjacent to a given node
11080  * and returns the number of selected nodes
11081  */
11082 static
11083 TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11085  int nadjnodes;
11086  int i;
11087 
11088  assert(tcliquegraph != NULL);
11089  assert(0 <= node && node < tcliquegraph->nnodes);
11090  assert(nnodes == 0 || nodes != NULL);
11091  assert(adjnodes != NULL);
11092 
11093  nadjnodes = 0;
11094 
11095  for( i = 0; i < nnodes; i++ )
11096  {
11097  /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11098  assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11099  assert(i == 0 || nodes[i-1] < nodes[i]);
11100 
11101  /* check if an edge exists */
11102  if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11103  {
11104  /* current node is adjacent to given node */
11105  adjnodes[nadjnodes] = nodes[i];
11106  nadjnodes++;
11107  }
11108  }
11109 
11110  return nadjnodes;
11111 }
11112 
11113 /** generates cuts using a clique found by algorithm for maximum weight clique
11114  * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11115  */
11116 static
11117 TCLIQUE_NEWSOL(tcliqueNewsolClique)
11118 { /*lint --e{715}*/
11119  SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11120 }
11121 
11122 /** print the tclique graph */
11123 #if 0
11124 static
11125 void tcliquePrint(
11126  SCIP* scip, /**< SCIP data structure */
11127  TCLIQUE_GRAPH* tcliquegraph /**< tclique graph */
11128  )
11129 {
11130  int nnodes;
11131  int i;
11132  int j;
11133 
11134  nnodes = tcliquegraph->nnodes;
11135 
11136  for( i = 0; i < nnodes; ++i )
11137  {
11138  for( j = 0; j < nnodes; ++j )
11139  {
11140  SCIPinfoMessage(scip, NULL, "(%d/%d) ", tcliquegraph->precedencematrix[i][j], tcliquegraph->demandmatrix[i][j]);
11141  }
11142  SCIPinfoMessage(scip, NULL, "\n");
11143  }
11144 }
11145 #endif
11146 
11147 /** @} */
11148 
11149 /** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11150  * job corresponding to variable bound variable (vlbvar)
11151  *
11152  * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11153  */
11154 static
11156  SCIP* scip, /**< SCIP data structure */
11157  SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11158  SCIP_Real vlbcoef, /**< variable bound coefficient */
11159  SCIP_Real vlbconst, /**< variable bound constant */
11160  int duration /**< duration of the variable bound variable */
11161  )
11162 {
11163  if( SCIPisEQ(scip, vlbcoef, 1.0) )
11164  {
11165  if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11166  {
11167  /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11168  return TRUE;
11169  }
11170  }
11171  else
11172  {
11173  SCIP_Real bound;
11174 
11175  bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11176 
11177  if( SCIPisLT(scip, vlbcoef, 1.0) )
11178  {
11179  SCIP_Real ub;
11180 
11181  ub = SCIPvarGetUbLocal(vlbvar);
11182 
11183  /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11184  if( SCIPisLE(scip, ub, bound) )
11185  return TRUE;
11186  }
11187  else
11188  {
11189  SCIP_Real lb;
11190 
11191  assert(SCIPisGT(scip, vlbcoef, 1.0));
11192 
11193  lb = SCIPvarGetLbLocal(vlbvar);
11194 
11195  /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11196  if( SCIPisGE(scip, lb, bound) )
11197  return TRUE;
11198  }
11199  }
11200 
11201  return FALSE;
11202 }
11203 
11204 /** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11205  * job corresponding to variable which is bounded (var)
11206  *
11207  * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11208  */
11209 static
11211  SCIP* scip, /**< SCIP data structure */
11212  SCIP_VAR* var, /**< variable which is bound from above */
11213  SCIP_Real vubcoef, /**< variable bound coefficient */
11214  SCIP_Real vubconst, /**< variable bound constant */
11215  int duration /**< duration of the variable which is bounded from above */
11216  )
11217 {
11218  SCIP_Real vlbcoef;
11219  SCIP_Real vlbconst;
11220 
11221  /* convert the variable upper bound into an variable lower bound */
11222  vlbcoef = 1.0 / vubcoef;
11223  vlbconst = -vubconst / vubcoef;
11224 
11225  return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11226 }
11227 
11228 /** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11229  * others an index larger than the number if active variables
11230  */
11231 static
11233  SCIP* scip, /**< SCIP data structure */
11234  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11235  SCIP_VAR* var, /**< variable for which we want the index */
11236  int* idx /**< pointer to store the index */
11237  )
11238 {
11239  (*idx) = SCIPvarGetProbindex(var);
11240 
11241  if( (*idx) == -1 )
11242  {
11243  if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11244  {
11245  (*idx) = (int)(size_t) SCIPhashmapGetImage(tcliquegraph->varmap, (void*)var);
11246  }
11247  else
11248  {
11249  int pos;
11250  int v;
11251 
11252  /**@todo we might want to add the aggregation path to graph */
11253 
11254  /* check if we have to realloc memory */
11255  if( tcliquegraph->size == tcliquegraph->nnodes )
11256  {
11257  int size;
11258 
11259  size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11260  tcliquegraph->size = size;
11261 
11262  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11263  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11264  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11265  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11266  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11267 
11268  for( v = 0; v < tcliquegraph->nnodes; ++v )
11269  {
11270  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11271  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11272  }
11273  }
11274  assert(tcliquegraph->nnodes < tcliquegraph->size);
11275 
11276  pos = tcliquegraph->nnodes;
11277  assert(pos >= 0);
11278 
11279  tcliquegraph->durations[pos] = 0;
11280  tcliquegraph->weights[pos] = 0;
11281  tcliquegraph->vars[pos] = var;
11282 
11283  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11284  BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11285 
11286  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11287  BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11288 
11289  SCIP_CALL( SCIPhashmapInsert(tcliquegraph->varmap, (void*)var, (void*)(size_t)(pos)) );
11290 
11291  tcliquegraph->nnodes++;
11292 
11293  for( v = 0; v < tcliquegraph->nnodes; ++v )
11294  {
11295  tcliquegraph->precedencematrix[v][pos] = 0;
11296  tcliquegraph->demandmatrix[v][pos] = 0;
11297  }
11298 
11299  (*idx) = tcliquegraph->nnodes;
11300  }
11301  }
11302  else
11303  {
11304  assert(*idx == (int)(size_t)SCIPhashmapGetImage(tcliquegraph->varmap, (void*)var));
11305  }
11306 
11307  assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11308 
11309  return SCIP_OKAY;
11310 }
11311 
11312 /** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11313  *
11314  * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11315  * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11316  *
11317  * (i) b = 1 and c >= d
11318  * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11319  * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11320  *
11321  */
11322 static
11324  SCIP* scip, /**< SCIP data structure */
11325  TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11326  )
11327 {
11328  SCIP_VAR** vars;
11329  int nvars;
11330  int v;
11331 
11332  vars = SCIPgetVars(scip);
11333  nvars = SCIPgetNVars(scip);
11334 
11335  /* try to project each arc of the variable bound graph to precedence condition */
11336  for( v = 0; v < nvars; ++v )
11337  {
11338  SCIP_VAR** vbdvars;
11339  SCIP_VAR* var;
11340  SCIP_Real* vbdcoefs;
11341  SCIP_Real* vbdconsts;
11342  int nvbdvars;
11343  int idx1;
11344  int b;
11345 
11346  var = vars[v];
11347  assert(var != NULL);
11348 
11349  SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11350  assert(idx1 >= 0);
11351 
11352  if( tcliquegraph->durations[idx1] == 0 )
11353  continue;
11354 
11355  vbdvars = SCIPvarGetVlbVars(var);
11356  vbdcoefs = SCIPvarGetVlbCoefs(var);
11357  vbdconsts = SCIPvarGetVlbConstants(var);
11358  nvbdvars = SCIPvarGetNVlbs(var);
11359 
11360  for( b = 0; b < nvbdvars; ++b )
11361  {
11362  int idx2;
11363 
11364  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11365  assert(idx2 >= 0);
11366 
11367  if( tcliquegraph->durations[idx2] == 0 )
11368  continue;
11369 
11370  if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11371  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11372  }
11373 
11374  vbdvars = SCIPvarGetVubVars(var);
11375  vbdcoefs = SCIPvarGetVubCoefs(var);
11376  vbdconsts = SCIPvarGetVubConstants(var);
11377  nvbdvars = SCIPvarGetNVubs(var);
11378 
11379  for( b = 0; b < nvbdvars; ++b )
11380  {
11381  int idx2;
11382 
11383  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11384  assert(idx2 >= 0);
11385 
11386  if( tcliquegraph->durations[idx2] == 0 )
11387  continue;
11388 
11389  if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11390  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11391  }
11392 
11393  for( b = v+1; b < nvars; ++b )
11394  {
11395  int idx2;
11396 
11397  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11398  assert(idx2 >= 0);
11399 
11400  if( tcliquegraph->durations[idx2] == 0 )
11401  continue;
11402 
11403  /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11404  if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11405  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11406 
11407  /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11408  if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11409  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11410  }
11411  }
11412 
11413  return SCIP_OKAY;
11414 }
11415 
11416 /** compute the transitive closer of the given graph and the number of in and out arcs */
11417 static
11418 void transitiveClosure(
11419  SCIP_Bool** adjmatrix, /**< adjacent matrix */
11420  int* ninarcs, /**< array to store the number of in arcs */
11421  int* noutarcs, /**< array to store the number of out arcs */
11422  int nnodes /**< number if nodes */
11423  )
11424 {
11425  int i;
11426  int j;
11427  int k;
11428 
11429  for( i = 0; i < nnodes; ++i )
11430  {
11431  for( j = 0; j < nnodes; ++j )
11432  {
11433  if( adjmatrix[i][j] )
11434  {
11435  ninarcs[j]++;
11436  noutarcs[i]++;
11437 
11438  for( k = 0; k < nnodes; ++k )
11439  {
11440  if( adjmatrix[j][k] )
11441  adjmatrix[i][k] = TRUE;
11442  }
11443  }
11444  }
11445  }
11446 }
11447 
11448 /** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11449 static
11451  SCIP* scip, /**< SCIP data structure */
11452  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11453  SCIP_CONS** conss, /**< array of cumulative constraints */
11454  int nconss /**< number of cumulative constraints */
11455  )
11456 {
11457  int c;
11458 
11459  /* use the cumulative constraints to initialize the none overlapping graph */
11460  for( c = 0; c < nconss; ++c )
11461  {
11462  SCIP_CONSDATA* consdata;
11463  SCIP_VAR** vars;
11464  int* demands;
11465  int capacity;
11466  int nvars;
11467  int i;
11468 
11469  consdata = SCIPconsGetData(conss[c]);
11470  assert(consdata != NULL);
11471 
11472  vars = consdata->vars;
11473  demands = consdata->demands;
11474 
11475  nvars = consdata->nvars;
11476  capacity = consdata->capacity;
11477 
11478  SCIPdebugMessage("constraint <%s>\n", SCIPconsGetName(conss[c]));
11479 
11480  /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11481  for( i = 0; i < nvars; ++i )
11482  {
11483  int idx1;
11484  int j;
11485 
11486  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11487  assert(idx1 >= 0);
11488 
11489  if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11490  continue;
11491 
11492  for( j = i+1; j < nvars; ++j )
11493  {
11494  assert(consdata->durations[j] > 0);
11495 
11496  if( demands[i] + demands[j] > capacity )
11497  {
11498  int idx2;
11499  int est1;
11500  int est2;
11501  int lct1;
11502  int lct2;
11503 
11504  /* check if the effective horizon is large enough */
11505  est1 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[i]));
11506  est2 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[j]));
11507 
11508  /* at least one of the jobs needs to start at hmin or later */
11509  if( est1 < consdata->hmin && est2 < consdata->hmin )
11510  continue;
11511 
11512  lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11513  lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11514 
11515  /* at least one of the jobs needs to finish not later then hmin */
11516  if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11517  continue;
11518 
11519  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11520  assert(idx2 >= 0);
11521  assert(idx1 != idx2);
11522 
11523  if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11524  continue;
11525 
11526  SCIPdebugMessage(" *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11527 
11528  assert(tcliquegraph->durations[idx1] > 0);
11529  assert(tcliquegraph->durations[idx2] > 0);
11530 
11531  tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11532  tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11533 
11534  }
11535  }
11536  }
11537  }
11538 
11539  return SCIP_OKAY;
11540 }
11541 
11542 /** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11543  * of jobs cannot run in parallel
11544  */
11545 static
11547  SCIP* scip, /**< SCIP data structure */
11548  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11549  SCIP_CONS** conss, /**< array of cumulative constraints */
11550  int nconss /**< number of cumulative constraints */
11551  )
11552 {
11553  assert(scip != NULL);
11554  assert(tcliquegraph != NULL);
11555 
11556  /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11557  SCIP_CALL( projectVbd(scip, tcliquegraph) );
11558 
11559  /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11560  transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11561 
11562  /* constraints non-overlapping graph */
11563  SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11564 
11565  return SCIP_OKAY;
11566 }
11567 
11568 /** create cumulative constraint from conflict set */
11569 static
11571  SCIP* scip, /**< SCIP data structure */
11572  const char* name, /**< constraint name */
11573  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11574  int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11575  int ncliquenodes /**< number of nodes in the clique */
11576  )
11577 {
11578  SCIP_CONS* cons;
11579  SCIP_VAR** vars;
11580  int* durations;
11581  int* demands;
11582  int v;
11583 
11584  SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11585  SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11586  SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11587 
11588  SCIPsortInt(cliquenodes, ncliquenodes);
11589 
11590  /* collect variables, durations, and demands */
11591  for( v = 0; v < ncliquenodes; ++v )
11592  {
11593  durations[v] = tcliquegraph->durations[cliquenodes[v]];
11594  assert(durations[v] > 0);
11595  demands[v] = 1;
11596  vars[v] = tcliquegraph->vars[cliquenodes[v]];
11597  }
11598 
11599  /* create (unary) cumulative constraint */
11600  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11602 
11603  SCIP_CALL( SCIPaddCons(scip, cons) );
11604  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11605 
11606  /* free buffers */
11607  SCIPfreeBufferArray(scip, &demands);
11608  SCIPfreeBufferArray(scip, &durations);
11609  SCIPfreeBufferArray(scip, &vars);
11610 
11611  return SCIP_OKAY;
11612 }
11613 
11614 /** search for cumulative constrainst */
11615 static
11617  SCIP* scip, /**< SCIP data structure */
11618  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11619  int* naddconss /**< pointer to store the number of added constraints */
11620  )
11621 {
11622  TCLIQUE_STATUS tcliquestatus;
11623  SCIP_Bool* precedencerow;
11624  SCIP_Bool* precedencecol;
11625  SCIP_Bool* demandrow;
11626  SCIP_Bool* demandcol;
11627  SCIP_HASHTABLE* covered;
11628  int* cliquenodes;
11629  int ncliquenodes;
11630  int cliqueweight;
11631  int ntreenodes;
11632  int nnodes;
11633  int nconss;
11634  int v;
11635 
11636  nnodes = tcliquegraph->nnodes;
11637  nconss = 0;
11638 
11639  /* initialize the weight of each job with its duration */
11640  for( v = 0; v < nnodes; ++v )
11641  {
11642  tcliquegraph->weights[v] = tcliquegraph->durations[v];
11643  }
11644 
11645  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11646  SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11647  SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11648  SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11649  SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11650 
11651  /* create a hash table to store all start time variables which are already covered by at least one clique */
11653  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11654 
11655  /* for each variables/job we are ... */
11656  for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11657  {
11658  char name[SCIP_MAXSTRLEN];
11659  int c;
11660 
11661  /* jobs with zero durations are skipped */
11662  if( tcliquegraph->durations[v] == 0 )
11663  continue;
11664 
11665  /* check if the start time variable is already covered by at least one clique */
11666  if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11667  continue;
11668 
11669  SCIPdebugMessage("********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11670 
11671  /* temporarily remove the connection via the precedence graph */
11672  for( c = 0; c < nnodes; ++c )
11673  {
11674  precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11675  precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11676 
11677  demandrow[c] = tcliquegraph->demandmatrix[v][c];
11678  demandcol[c] = tcliquegraph->demandmatrix[c][v];
11679 
11680 #if 0
11681  if( precedencerow[c] || precedencecol[c] )
11682  {
11683  tcliquegraph->demandmatrix[v][c] = FALSE;
11684  tcliquegraph->demandmatrix[c][v] = FALSE;
11685  }
11686 #endif
11687 
11688  tcliquegraph->precedencematrix[c][v] = FALSE;
11689  tcliquegraph->precedencematrix[v][c] = FALSE;
11690  }
11691 
11692  /* find (heuristically) maximum cliques which includes node v */
11693  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11694  tcliquegraph, tcliqueNewsolClique, NULL,
11695  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11696  10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11697 
11698  SCIPdebugMessage("tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11699 
11700  if( ncliquenodes == 1 )
11701  continue;
11702 
11703  /* construct constraint name */
11704  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11705 
11706  SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11707  nconss++;
11708 
11709  /* all start time variable to covered hash table */
11710  for( c = 0; c < ncliquenodes; ++c )
11711  {
11712  SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11713  }
11714 
11715  /* copy the precedence relations back */
11716  for( c = 0; c < nnodes; ++c )
11717  {
11718  tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11719  tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11720 
11721  tcliquegraph->demandmatrix[v][c] = demandrow[c];
11722  tcliquegraph->demandmatrix[c][v] = demandcol[c];
11723  }
11724  }
11725 
11726  SCIPhashtableFree(&covered);
11727 
11728  SCIPfreeBufferArray(scip, &demandcol);
11729  SCIPfreeBufferArray(scip, &demandrow);
11730  SCIPfreeBufferArray(scip, &precedencecol);
11731  SCIPfreeBufferArray(scip, &precedencerow);
11732  SCIPfreeBufferArray(scip, &cliquenodes);
11733 
11734  (*naddconss) += nconss;
11735 
11736  /* for the statistic we count the number added disjunctive constraints */
11737  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11738 
11739  return SCIP_OKAY;
11740 }
11741 
11742 /** create precedence constraint (as variable bound constraint */
11743 static
11745  SCIP* scip, /**< SCIP data structure */
11746  const char* name, /**< constraint name */
11747  SCIP_VAR* var, /**< variable x that has variable bound */
11748  SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11749  int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11750  )
11751 {
11752  SCIP_CONS* cons;
11753 
11754  /* create variable bound constraint */
11755  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11757 
11758  SCIPdebugPrintCons(scip, cons, NULL);
11759 
11760  /* add constraint to problem and release it */
11761  SCIP_CALL( SCIPaddCons(scip, cons) );
11762  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11763 
11764  return SCIP_OKAY;
11765 }
11766 
11767 /** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11768 static
11770  SCIP* scip, /**< SCIP data structure */
11771  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11772  int source, /**< index of the source node */
11773  int sink, /**< index of the sink node */
11774  int* naddconss /**< pointer to store the number of added constraints */
11775  )
11776 {
11777  TCLIQUE_WEIGHT cliqueweight;
11778  TCLIQUE_STATUS tcliquestatus;
11779  SCIP_VAR** vars;
11780  int* cliquenodes;
11781  int nnodes;
11782  int lct;
11783  int est;
11784  int i;
11785 
11786  int ntreenodes;
11787  int ncliquenodes;
11788 
11789  /* check if source and sink are connencted */
11790  if( !tcliquegraph->precedencematrix[source][sink] )
11791  return SCIP_OKAY;
11792 
11793  nnodes = tcliquegraph->nnodes;
11794  vars = tcliquegraph->vars;
11795 
11796  /* reset the weights to zero */
11797  BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11798 
11799  /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11800  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11801  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[sink]));
11802 
11803  /* weight all jobs which run for sure between source and sink with their duration */
11804  for( i = 0; i < nnodes; ++i )
11805  {
11806  SCIP_VAR* var;
11807  int duration;
11808 
11809  var = vars[i];
11810  assert(var != NULL);
11811 
11812  duration = tcliquegraph->durations[i];
11813 
11814  if( i == source || i == sink )
11815  {
11816  /* source and sink are not weighted */
11817  tcliquegraph->weights[i] = 0;
11818  }
11819  else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11820  {
11821  /* job i runs after source and before sink */
11822  tcliquegraph->weights[i] = duration;
11823  }
11824  else if( lct <= SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var))
11825  && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11826  {
11827  /* job i run in between due the bounds of the start time variables */
11828  tcliquegraph->weights[i] = duration;
11829  }
11830  else
11831  tcliquegraph->weights[i] = 0;
11832  }
11833 
11834  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11835 
11836  /* find (heuristically) maximum cliques */
11837  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11838  tcliquegraph, tcliqueNewsolClique, NULL,
11839  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11840  10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11841 
11842  if( ncliquenodes > 1 )
11843  {
11844  char name[SCIP_MAXSTRLEN];
11845  int distance;
11846 
11847  /* construct constraint name */
11848  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11849 
11850  /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11851  * duration of the source job
11852  */
11853  distance = cliqueweight + tcliquegraph->durations[source];
11854 
11855  SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11856  (*naddconss)++;
11857  }
11858 
11859  SCIPfreeBufferArray(scip, &cliquenodes);
11860 
11861  return SCIP_OKAY;
11862 }
11863 
11864 /** search for precedence constraints
11865  *
11866  * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
11867  * corresponding two jobs
11868  */
11869 static
11871  SCIP* scip, /**< SCIP data structure */
11872  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11873  int* naddconss /**< pointer to store the number of added constraints */
11874  )
11875 {
11876  int* sources;
11877  int* sinks;
11878  int nconss;
11879  int nnodes;
11880  int nsources;
11881  int nsinks;
11882  int i;
11883 
11884  nnodes = tcliquegraph->nnodes;
11885  nconss = 0;
11886 
11887  nsources = 0;
11888  nsinks = 0;
11889 
11890  SCIP_CALL( SCIPallocBufferArray(scip, &sources, nnodes) );
11891  SCIP_CALL( SCIPallocBufferArray(scip, &sinks, nnodes) );
11892 
11893  /* first collect all sources and sinks */
11894  for( i = 0; i < nnodes; ++i )
11895  {
11896  if( tcliquegraph->ninarcs[i] == 0 )
11897  {
11898  sources[nsources] = i;
11899  nsources++;
11900  }
11901 
11902  if( tcliquegraph->ninarcs[i] == 0 )
11903  {
11904  sinks[nsinks] = i;
11905  nsinks++;
11906  }
11907  }
11908 
11909  /* compute for each node a minimum distance to each sources and each sink */
11910  for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
11911  {
11912  int j;
11913 
11914  for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
11915  {
11916  SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
11917  }
11918 
11919  for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
11920  {
11921  SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
11922  }
11923  }
11924 
11925  (*naddconss) += nconss;
11926 
11927  /* for the statistic we count the number added variable constraints */
11928  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
11929 
11930  SCIPfreeBufferArray(scip, &sinks);
11931  SCIPfreeBufferArray(scip, &sources);
11932 
11933  return SCIP_OKAY;
11934 }
11935 
11936 /** initialize the assumed durations for each variable */
11937 static
11939  SCIP* scip, /**< SCIP data structure */
11940  TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
11941  SCIP_CONS** conss, /**< cumulative constraints */
11942  int nconss /**< number of cumulative constraints */
11943  )
11944 {
11945  int c;
11946 
11947  /* use the cumulative structure to define the duration we are using for each job */
11948  for( c = 0; c < nconss; ++c )
11949  {
11950  SCIP_CONSDATA* consdata;
11951  SCIP_VAR** vars;
11952  int nvars;
11953  int v;
11954 
11955  consdata = SCIPconsGetData(conss[c]);
11956  assert(consdata != NULL);
11957 
11958  vars = consdata->vars;
11959  nvars = consdata->nvars;
11960 
11961  for( v = 0; v < nvars; ++v )
11962  {
11963  int idx;
11964 
11965  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
11966  assert(idx >= 0);
11967 
11968  /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
11969  * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
11970  * general this is not the case. Therefore, the question would be which duration should be used?
11971  */
11972  tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
11973  assert(tcliquegraph->durations[idx] > 0);
11974  }
11975  }
11976 
11977  return SCIP_OKAY;
11978 }
11979 
11980 /** create tclique graph */
11981 static
11983  SCIP* scip, /**< SCIP data structure */
11984  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
11985  )
11986 {
11987  SCIP_VAR** vars;
11988  SCIP_HASHMAP* varmap;
11989  SCIP_Bool** precedencematrix;
11990  SCIP_Bool** demandmatrix;
11991  int* ninarcs;
11992  int* noutarcs;
11993  int* durations;
11994  int* weights;
11995  int nvars;
11996  int v;
11997 
11998  vars = SCIPgetVars(scip);
11999  nvars = SCIPgetNVars(scip);
12000 
12001  /* allocate memory for the tclique graph data structure */
12002  SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12003 
12004  /* create the variable mapping hash map */
12005  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), SCIPcalcHashtableSize(5 * nvars)) );
12006 
12007  /* each active variables get a node in the graph */
12008  SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12009 
12010  /* allocate memory for the projected variables bound graph and the none overlapping graph */
12011  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12012  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12013 
12014  /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12015  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12016  BMSclearMemoryArray(weights, nvars);
12017 
12018  /* array to store the number of in arc of the precedence graph */
12019  SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12020  BMSclearMemoryArray(ninarcs, nvars);
12021 
12022  /* array to store the number of out arc of the precedence graph */
12023  SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12024  BMSclearMemoryArray(noutarcs, nvars);
12025 
12026  /* array to store the used duration for each node */
12027  SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12028  BMSclearMemoryArray(durations, nvars);
12029 
12030  for( v = 0; v < nvars; ++v )
12031  {
12032  SCIP_VAR* var;
12033 
12034  var = vars[v];
12035  assert(var != NULL);
12036 
12037  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12038  BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12039 
12040  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12041  BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12042 
12043  /* insert all active variables into the garph */
12044  assert(SCIPvarGetProbindex(var) == v);
12045  SCIP_CALL( SCIPhashmapInsert(varmap, (void*)var, (void*)(size_t)v) ); /*lint !e571*/
12046  }
12047 
12048  (*tcliquegraph)->nnodes = nvars;
12049  (*tcliquegraph)->varmap = varmap;
12050  (*tcliquegraph)->precedencematrix = precedencematrix;
12051  (*tcliquegraph)->demandmatrix = demandmatrix;
12052  (*tcliquegraph)->weights = weights;
12053  (*tcliquegraph)->ninarcs = ninarcs;
12054  (*tcliquegraph)->noutarcs = noutarcs;
12055  (*tcliquegraph)->durations = durations;
12056  (*tcliquegraph)->size = nvars;
12057 
12058  return SCIP_OKAY;
12059 }
12060 
12061 /** frees the tclique graph */
12062 static
12063 void freeTcliqueGraph(
12064  SCIP* scip, /**< SCIP data structure */
12065  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12066  )
12067 {
12068  int v;
12069 
12070  for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12071  {
12072  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12073  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12074  }
12075 
12076  SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12077  SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12078  SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12079  SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12080  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12081  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12082  SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12083  SCIPhashmapFree(&(*tcliquegraph)->varmap);
12084 
12085  SCIPfreeBuffer(scip, tcliquegraph);
12086 }
12087 
12088 /** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12089  * constrains (disjunctive constraint)
12090  */
12091 static
12093  SCIP* scip, /**< SCIP data structure */
12094  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12095  SCIP_CONS** conss, /**< array of cumulative constraints */
12096  int nconss, /**< number of cumulative constraints */
12097  int* naddconss /**< pointer to store the number of added constraints */
12098  )
12099 {
12100  TCLIQUE_GRAPH* tcliquegraph;
12101 
12102  /* create tclique graph */
12103  SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12104 
12105  /* define for each job a duration */
12106  SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12107 
12108  /* constuct incompatibility graph */
12109  SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12110 
12111  /* search for new precedence constraints */
12112  if( conshdlrdata->detectvarbounds )
12113  {
12114  SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12115  }
12116 
12117  /* search for new cumulative constraints */
12118  if( conshdlrdata->detectdisjunctive )
12119  {
12120  SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12121  }
12122 
12123  /* free tclique graph data structure */
12124  freeTcliqueGraph(scip, &tcliquegraph);
12125 
12126  return SCIP_OKAY;
12127 }
12128 
12129 /** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12130 static
12132  SCIP_CONSDATA* consdata /**< cumulative constraint data */
12133  )
12134 {
12135  SCIP_VAR** vars;
12136  int nvars;
12137  int v;
12138 
12139  if( consdata->validsignature )
12140  return;
12141 
12142  vars = consdata->vars;
12143  nvars = consdata->nvars;
12144 
12145  for( v = 0; v < nvars; ++v )
12146  {
12147  consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12148  }
12149 
12150  consdata->validsignature = TRUE;
12151 }
12152 
12153 /** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12154 static
12155 SCIP_DECL_SORTINDCOMP(consdataCompVar)
12156 { /*lint --e{715}*/
12157  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12158 
12159  assert(consdata != NULL);
12160  assert(0 <= ind1 && ind1 < consdata->nvars);
12161  assert(0 <= ind2 && ind2 < consdata->nvars);
12162 
12163  return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12164 }
12165 
12166 /** run a pairwise comparison */
12167 static
12169  SCIP* scip, /**< SCIP data structure */
12170  SCIP_CONS** conss, /**< array of cumulative constraints */
12171  int nconss, /**< number of cumulative constraints */
12172  int* ndelconss /**< pointer to store the number of deletedconstraints */
12173  )
12174 {
12175  int i;
12176  int j;
12177 
12178  for( i = 0; i < nconss; ++i )
12179  {
12180  SCIP_CONSDATA* consdata0;
12181  SCIP_CONS* cons0;
12182 
12183  cons0 = conss[i];
12184  assert(cons0 != NULL);
12185 
12186  consdata0 = SCIPconsGetData(cons0);
12187  assert(consdata0 != NULL);
12188 
12189  consdataCalcSignature(consdata0);
12190  assert(consdata0->validsignature);
12191 
12192  for( j = i+1; j < nconss; ++j )
12193  {
12194  SCIP_CONSDATA* consdata1;
12195  SCIP_CONS* cons1;
12196 
12197  cons1 = conss[j];
12198  assert(cons1 != NULL);
12199 
12200  consdata1 = SCIPconsGetData(cons1);
12201  assert(consdata1 != NULL);
12202 
12203  if( consdata0->capacity != consdata1->capacity )
12204  continue;
12205 
12206  consdataCalcSignature(consdata1);
12207  assert(consdata1->validsignature);
12208 
12209  if( (consdata1->signature & (~consdata0->signature)) == 0 )
12210  {
12211  SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12212  SCIPswapPointers((void**)&cons0, (void**)&cons1);
12213  assert((consdata0->signature & (~consdata1->signature)) == 0);
12214  }
12215 
12216  if( (consdata0->signature & (~consdata1->signature)) == 0 )
12217  {
12218  int* perm0;
12219  int* perm1;
12220  int v0;
12221  int v1;
12222 
12223  if( consdata0->nvars > consdata1->nvars )
12224  continue;
12225 
12226  if( consdata0->hmin < consdata1->hmin )
12227  continue;
12228 
12229  if( consdata0->hmax > consdata1->hmax )
12230  continue;
12231 
12232  SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12233  SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12234 
12235  /* call sorting method */
12236  SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12237  SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12238 
12239  for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12240  {
12241  SCIP_VAR* var0;
12242  SCIP_VAR* var1;
12243  int idx0;
12244  int idx1;
12245  int comp;
12246 
12247  idx0 = perm0[v0];
12248  idx1 = perm1[v1];
12249 
12250  var0 = consdata0->vars[idx0];
12251 
12252  var1 = consdata1->vars[idx1];
12253 
12254  comp = SCIPvarCompare(var0, var1);
12255 
12256  if( comp == 0 )
12257  {
12258  int duration0;
12259  int duration1;
12260  int demand0;
12261  int demand1;
12262 
12263  demand0 = consdata0->demands[idx0];
12264  duration0 = consdata0->durations[idx0];
12265 
12266  demand1 = consdata1->demands[idx1];
12267  duration1 = consdata1->durations[idx1];
12268 
12269  if( demand0 != demand1 )
12270  break;
12271 
12272  if( duration0 != duration1 )
12273  break;
12274 
12275  v0++;
12276  v1++;
12277  }
12278  else if( comp > 0 )
12279  v1++;
12280  else
12281  break;
12282  }
12283 
12284  if( v0 == consdata0->nvars )
12285  {
12286  if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12287  {
12288  initializeLocks(consdata1, TRUE);
12289  }
12290 
12291  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12292 
12293  SCIP_CALL( SCIPdelCons(scip, cons0) );
12294  (*ndelconss)++;
12295  }
12296 
12297  SCIPfreeBufferArray(scip, &perm1);
12298  SCIPfreeBufferArray(scip, &perm0);
12299  }
12300  }
12301  }
12302 
12303  return SCIP_OKAY;
12304 }
12305 
12306 /** strength the variable bounds using the cumulative condition */
12307 static
12309  SCIP* scip, /**< SCIP data structure */
12310  SCIP_CONS* cons, /**< constraint to propagate */
12311  int* nchgbds, /**< pointer to store the number of changed bounds */
12312  int* naddconss /**< pointer to store the number of added constraints */
12313  )
12314 {
12315  SCIP_CONSDATA* consdata;
12316  SCIP_VAR** vars;
12317  int* durations;
12318  int* demands;
12319  int capacity;
12320  int nvars;
12321  int nconss;
12322  int i;
12323 
12324  consdata = SCIPconsGetData(cons);
12325  assert(consdata != NULL);
12326 
12327  /* check if the variable bounds got already strengthen by the cumulative constraint */
12328  if( consdata->varbounds )
12329  return SCIP_OKAY;
12330 
12331  vars = consdata->vars;
12332  durations = consdata->durations;
12333  demands = consdata->demands;
12334  capacity = consdata->capacity;
12335  nvars = consdata->nvars;
12336 
12337  nconss = 0;
12338 
12339  for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12340  {
12341  SCIP_VAR** vbdvars;
12342  SCIP_VAR* var;
12343  SCIP_Real* vbdcoefs;
12344  SCIP_Real* vbdconsts;
12345  int nvbdvars;
12346  int b;
12347  int j;
12348 
12349  var = consdata->vars[i];
12350  assert(var != NULL);
12351 
12352  vbdvars = SCIPvarGetVlbVars(var);
12353  vbdcoefs = SCIPvarGetVlbCoefs(var);
12354  vbdconsts = SCIPvarGetVlbConstants(var);
12355  nvbdvars = SCIPvarGetNVlbs(var);
12356 
12357  for( b = 0; b < nvbdvars; ++b )
12358  {
12359  if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12360  {
12361  if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12362  {
12363  for( j = 0; j < nvars; ++j )
12364  {
12365  if( vars[j] == vbdvars[b] )
12366  break;
12367  }
12368  if( j == nvars )
12369  continue;
12370 
12371  if( demands[i] + demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12372  {
12373  SCIP_Bool infeasible;
12374  char name[SCIP_MAXSTRLEN];
12375  int nlocalbdchgs;
12376 
12377  SCIPdebugMessage("<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12378 
12379  /* construct constraint name */
12380  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12381 
12382  SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12383  nconss++;
12384 
12385  SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12386  assert(!infeasible);
12387 
12388  (*nchgbds) += nlocalbdchgs;
12389  }
12390  }
12391  }
12392  }
12393  }
12394 
12395  (*naddconss) += nconss;
12396 
12397  consdata->varbounds = TRUE;
12398 
12399  return SCIP_OKAY;
12400 }
12401 
12402 /**@} */
12403 
12404 
12405 /**@name Callback methods of constraint handler
12406  *
12407  * @{
12408  */
12409 
12410 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12411 static
12412 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12413 { /*lint --e{715}*/
12414  assert(scip != NULL);
12415  assert(conshdlr != NULL);
12416  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12417 
12418  /* call inclusion method of constraint handler */
12420 
12422 
12423  *valid = TRUE;
12424 
12425  return SCIP_OKAY;
12426 }
12427 
12428 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12429 static
12430 SCIP_DECL_CONSFREE(consFreeCumulative)
12431 { /*lint --e{715}*/
12432  SCIP_CONSHDLRDATA* conshdlrdata;
12433 
12434  assert(conshdlr != NULL);
12435  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12436 
12437  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12438  assert(conshdlrdata != NULL);
12439 
12440 #ifdef SCIP_STATISTIC
12441  if( !conshdlrdata->iscopy )
12442  {
12443  /* statisitc output if SCIP_STATISTIC is defined */
12444  SCIPstatisticPrintf("time-table: lb=%"SCIP_LONGINT_FORMAT", ub=%"SCIP_LONGINT_FORMAT", cutoff=%"SCIP_LONGINT_FORMAT"\n",
12445  conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12446  SCIPstatisticPrintf("edge-finder: lb=%"SCIP_LONGINT_FORMAT", ub=%"SCIP_LONGINT_FORMAT", cutoff=%"SCIP_LONGINT_FORMAT"\n",
12447  conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12448  SCIPstatisticPrintf("overload: time-table=%"SCIP_LONGINT_FORMAT" time-time edge-finding=%"SCIP_LONGINT_FORMAT"\n",
12449  conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12450  }
12451 #endif
12452 
12453  conshdlrdataFree(scip, &conshdlrdata);
12454 
12455  SCIPconshdlrSetData(conshdlr, NULL);
12456 
12457  return SCIP_OKAY;
12458 }
12459 
12460 
12461 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12462 static
12463 SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12464 { /*lint --e{715}*/
12465  int c;
12466 
12467  for( c = 0; c < nconss; ++c )
12468  {
12469  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12470  * hmax)
12471  */
12472  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12473  }
12474 
12475  return SCIP_OKAY;
12476 }
12477 
12478 
12479 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12480 #ifdef SCIP_STATISTIC
12481 static
12482 SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12483 { /*lint --e{715}*/
12484  SCIP_CONSHDLRDATA* conshdlrdata;
12485  int c;
12486 
12487  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12488  assert(conshdlrdata != NULL);
12489 
12490  for( c = 0; c < nconss; ++c )
12491  {
12492  SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12493 
12494 #if 0
12495  SCIP_CALL( SCIPvisualizeConsCumulative(scip, conss[c]) );
12496 #endif
12497  }
12498 
12499  if( !conshdlrdata->iscopy )
12500  {
12501  SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12502  SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12503  SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12504  SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12505  SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12506  SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12507  SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12508  SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12509  SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12510  }
12511 
12512  return SCIP_OKAY;
12513 }
12514 #endif
12515 
12516 
12517 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12518 static
12519 SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12520 { /*lint --e{715}*/
12521  SCIP_CONSDATA* consdata;
12522  int c;
12523 
12524  assert(conshdlr != NULL);
12525  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12526 
12527  /* release the rows of all constraints */
12528  for( c = 0; c < nconss; ++c )
12529  {
12530  consdata = SCIPconsGetData(conss[c]);
12531  assert(consdata != NULL);
12532 
12533  /* free rows */
12534  SCIP_CALL( consdataFreeRows(scip, &consdata) );
12535  }
12536 
12537  return SCIP_OKAY;
12538 }
12539 
12540 /** frees specific constraint data */
12541 static
12542 SCIP_DECL_CONSDELETE(consDeleteCumulative)
12543 { /*lint --e{715}*/
12544  assert(conshdlr != NULL);
12545  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12546  assert(consdata != NULL );
12547  assert(*consdata != NULL );
12548 
12549  /* if constraint belongs to transformed problem space, drop bound change events on variables */
12550  if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12551  {
12552  SCIP_CONSHDLRDATA* conshdlrdata;
12553 
12554  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12555  assert(conshdlrdata != NULL);
12556 
12557  SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12558  }
12559 
12560  /* free cumulative constraint data */
12561  SCIP_CALL( consdataFree(scip, consdata) );
12562 
12563  return SCIP_OKAY;
12564 }
12565 
12566 /** transforms constraint data into data belonging to the transformed problem */
12567 static
12568 SCIP_DECL_CONSTRANS(consTransCumulative)
12569 { /*lint --e{715}*/
12570  SCIP_CONSHDLRDATA* conshdlrdata;
12571  SCIP_CONSDATA* sourcedata;
12572  SCIP_CONSDATA* targetdata;
12573 
12574  assert(conshdlr != NULL);
12575  assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
12576  assert(sourcecons != NULL);
12577  assert(targetcons != NULL);
12578 
12579  sourcedata = SCIPconsGetData(sourcecons);
12580  assert(sourcedata != NULL);
12581  assert(sourcedata->demandrows == NULL);
12582 
12583  SCIPdebugMessage("transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12584 
12585  /* get event handler */
12586  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12587  assert(conshdlrdata != NULL);
12588  assert(conshdlrdata->eventhdlr != NULL);
12589 
12590  /* create constraint data for target constraint */
12591  SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12592  sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12593  sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12594 
12595  /* create target constraint */
12596  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12597  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12598  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12599  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12600  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12601 
12602  /* catch bound change events of variables */
12603  SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12604 
12605  return SCIP_OKAY;
12606 }
12607 
12608 /** LP initialization method of constraint handler */
12609 static
12610 SCIP_DECL_CONSINITLP(consInitlpCumulative)
12612  SCIP_CONSHDLRDATA* conshdlrdata;
12613  int c;
12614 
12615  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12616  assert(conshdlr != NULL);
12617  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12618  assert(conshdlrdata != NULL);
12619 
12620  SCIPdebugMessage("initialize LP relaxation for %d cumulative constraints\n", nconss);
12621 
12622  if( conshdlrdata->usebinvars )
12623  {
12624  /* add rows to LP */
12625  for( c = 0; c < nconss; ++c )
12626  {
12627  assert(SCIPconsIsInitial(conss[c]));
12628  SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss) );
12629 
12630  if( conshdlrdata->cutsasconss )
12631  {
12632  SCIP_CALL( SCIPrestartSolve(scip) );
12633  }
12634  }
12635  }
12636 
12637  /**@todo if we want to use only the integer variables; only these will be in cuts
12638  * create some initial cuts, currently these are only separated */
12639 
12640  return SCIP_OKAY;
12641 }
12642 
12643 /** separation method of constraint handler for LP solutions */
12644 static
12645 SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12647  SCIP_CONSHDLRDATA* conshdlrdata;
12648  SCIP_Bool cutoff;
12649  SCIP_Bool reducedom;
12650  SCIP_Bool separated;
12651  int c;
12652 
12653  SCIPdebugMessage("consSepalpCumulative\n");
12654 
12655  assert(conshdlr != NULL);
12656  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12657  assert(nconss == 0 || conss != NULL);
12658  assert(result != NULL);
12659  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12660  assert(conshdlrdata != NULL);
12661 
12662  SCIPdebugMessage("separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12663 
12664  cutoff = FALSE;
12665  reducedom = FALSE;
12666  separated = FALSE;
12667  (*result) = SCIP_DIDNOTRUN;
12668 
12669  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12670  return SCIP_OKAY;
12671 
12672  (*result) = SCIP_DIDNOTFIND;
12673 
12674  if( conshdlrdata->usebinvars )
12675  {
12676  /* check all useful cumulative constraints for feasibility */
12677  for( c = 0; c < nusefulconss && !reducedom && !cutoff; ++c )
12678  {
12679  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12680  }
12681 
12682  if( !cutoff && !reducedom && conshdlrdata->usecovercuts )
12683  {
12684  for( c = 0; c < nusefulconss; ++c )
12685  {
12686  SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12687  }
12688  }
12689  }
12690 
12691  if( conshdlrdata->sepaold )
12692  {
12693  /* separate cuts containing only integer variables */
12694  for( c = 0; c < nusefulconss; ++c )
12695  {
12696  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated) );
12697  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated) );
12698  }
12699  }
12700 
12701  if( cutoff )
12702  *result = SCIP_CUTOFF;
12703  else if( reducedom )
12704  *result = SCIP_REDUCEDDOM;
12705  else if( separated )
12706  *result = SCIP_SEPARATED;
12707 
12708  return SCIP_OKAY;
12709 }
12710 
12711 /** separation method of constraint handler for arbitrary primal solutions */
12712 static
12713 SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12714 { /*lint --e{715}*/
12715  SCIP_CONSHDLRDATA* conshdlrdata;
12716  SCIP_Bool cutoff;
12717  SCIP_Bool reducedom;
12718  SCIP_Bool separated;
12719  int c;
12720 
12721  assert(conshdlr != NULL);
12722  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12723  assert(nconss == 0 || conss != NULL);
12724  assert(result != NULL);
12725 
12726  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12727  assert(conshdlrdata != NULL);
12728 
12729  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12730  return SCIP_OKAY;
12731 
12732  SCIPdebugMessage("separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12733 
12734  cutoff = FALSE;
12735  reducedom = FALSE;
12736  separated = FALSE;
12737  (*result) = SCIP_DIDNOTFIND;
12738 
12739  if( conshdlrdata->usebinvars )
12740  {
12741  /* check all useful cumulative constraints for feasibility */
12742  for( c = 0; c < nusefulconss && !cutoff && !reducedom; ++c )
12743  {
12744  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12745  }
12746 
12747  if( !cutoff && !reducedom && conshdlrdata->usecovercuts )
12748  {
12749  for( c = 0; c < nusefulconss; ++c )
12750  {
12751  SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12752  }
12753  }
12754  }
12755  if( conshdlrdata->sepaold )
12756  {
12757  /* separate cuts containing only integer variables */
12758  for( c = 0; c < nusefulconss; ++c )
12759  {
12760  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated) );
12761  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated) );
12762  }
12763  }
12764 
12765  if( cutoff )
12766  *result = SCIP_CUTOFF;
12767  else if( reducedom )
12768  *result = SCIP_REDUCEDDOM;
12769  else if( separated )
12770  *result = SCIP_SEPARATED;
12771 
12772  return SCIP_OKAY;
12773 }
12774 
12775 /** constraint enforcing method of constraint handler for LP solutions */
12776 static
12777 SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
12778 { /*lint --e{715}*/
12779  SCIP_CONSHDLRDATA* conshdlrdata;
12780 
12781  assert(conshdlr != NULL);
12782  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12783  assert(nconss == 0 || conss != NULL);
12784  assert(result != NULL);
12785 
12786  if( solinfeasible )
12787  {
12788  *result = SCIP_INFEASIBLE;
12789  return SCIP_OKAY;
12790  }
12791 
12792  SCIPdebugMessage("LP enforcing %d useful cumulative constraints of %d constraints\n", nusefulconss, nconss);
12793 
12794  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12795  assert(conshdlrdata != NULL);
12796 
12797  (*result) = SCIP_FEASIBLE;
12798 
12799  if( conshdlrdata->usebinvars )
12800  {
12801  SCIP_Bool separated;
12802  SCIP_Bool cutoff;
12803  int c;
12804 
12805  separated = FALSE;
12806 
12807  /* first check if a constraints is violated */
12808  for( c = 0; c < nusefulconss; ++c )
12809  {
12810  SCIP_CONS* cons;
12811  SCIP_Bool violated;
12812 
12813  cons = conss[c];
12814  assert(cons != NULL);
12815 
12816  SCIP_CALL( checkCons(scip, cons, NULL, &violated, FALSE) );
12817 
12818  if( !violated )
12819  continue;
12820 
12821  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, NULL, &separated, &cutoff) );
12822  if ( cutoff )
12823  {
12824  *result = SCIP_CUTOFF;
12825  return SCIP_OKAY;
12826  }
12827  }
12828 
12829  for( ; c < nconss && !separated; ++c )
12830  {
12831  SCIP_CONS* cons;
12832  SCIP_Bool violated;
12833 
12834  cons = conss[c];
12835  assert(cons != NULL);
12836 
12837  SCIP_CALL( checkCons(scip, cons, NULL, &violated, FALSE) );
12838 
12839  if( !violated )
12840  continue;
12841 
12842  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, NULL, &separated, &cutoff) );
12843  if ( cutoff )
12844  {
12845  *result = SCIP_CUTOFF;
12846  return SCIP_OKAY;
12847  }
12848  }
12849 
12850  if( separated )
12851  (*result) = SCIP_SEPARATED;
12852  }
12853  else
12854  {
12855  SCIP_CALL( enforceSolution(scip, conss, nconss, conshdlrdata->fillbranchcands, result) );
12856  }
12857 
12858  return SCIP_OKAY;
12859 }
12860 
12861 /** constraint enforcing method of constraint handler for pseudo solutions */
12862 static
12863 SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
12864 { /*lint --e{715}*/
12865  SCIP_CONSHDLRDATA* conshdlrdata;
12866 
12867  SCIPdebugMessage("method: enforce pseudo solution\n");
12868 
12869  assert(conshdlr != NULL);
12870  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12871  assert(nconss == 0 || conss != NULL);
12872  assert(result != NULL);
12873 
12874  if( objinfeasible )
12875  {
12876  *result = SCIP_DIDNOTRUN;
12877  return SCIP_OKAY;
12878  }
12879 
12880  (*result) = SCIP_FEASIBLE;
12881 
12882  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12883  assert(conshdlrdata != NULL);
12884 
12885  SCIP_CALL( enforceSolution(scip, conss, nconss, conshdlrdata->fillbranchcands, result) );
12886 
12887  return SCIP_OKAY;
12888 }
12889 
12890 /** feasibility check method of constraint handler for integral solutions */
12891 static
12892 SCIP_DECL_CONSCHECK(consCheckCumulative)
12893 { /*lint --e{715}*/
12894  SCIP_Bool violated;
12895  int c;
12896 
12897  assert(conshdlr != NULL);
12898  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12899  assert(nconss == 0 || conss != NULL);
12900  assert(result != NULL);
12901 
12902  violated = FALSE;
12903 
12904  SCIPdebugMessage("check %d cumulative constraints\n", nconss);
12905 
12906  for( c = 0; c < nconss && !violated; ++c )
12907  {
12908  SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
12909  }
12910 
12911  if( violated )
12912  *result = SCIP_INFEASIBLE;
12913  else
12914  *result = SCIP_FEASIBLE;
12915 
12916  return SCIP_OKAY;
12917 }
12918 
12919 /** domain propagation method of constraint handler */
12920 static
12921 SCIP_DECL_CONSPROP(consPropCumulative)
12922 { /*lint --e{715}*/
12923  SCIP_CONSHDLRDATA* conshdlrdata;
12924  SCIP_Bool cutoff;
12925  int nchgbds;
12926  int ndelconss;
12927  int c;
12928 #if 0
12929  int naggrvars = 0;
12930 #endif
12931 
12932  SCIPdebugMessage("propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
12933 
12934  assert(conshdlr != NULL);
12935  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12936  assert(nconss == 0 || conss != NULL);
12937  assert(result != NULL);
12938 
12939  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12940  assert(conshdlrdata != NULL);
12941 
12942  nchgbds = 0;
12943  ndelconss = 0;
12944  cutoff = FALSE;
12945  (*result) = SCIP_DIDNOTRUN;
12946 
12947  /* propgate all useful constraints */
12948  for( c = 0; c < nusefulconss && !cutoff; ++c )
12949  {
12950  SCIP_CONS* cons;
12951 
12952  cons = conss[c];
12953  assert(cons != NULL);
12954 
12955  if( SCIPgetDepth(scip) == 0 )
12956  {
12957 #if 0
12958  SCIP_CALL( presolveCons(scip, cons, conshdlrdata,
12959  &nchgbds, &naggrvars, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
12960 #else
12961  SCIP_CALL( presolveCons(scip, cons, conshdlrdata,
12962  &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
12963 #endif
12964  if( cutoff )
12965  break;
12966 
12967  if( SCIPconsIsDeleted(cons) )
12968  continue;
12969  }
12970 
12971  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, &nchgbds, &ndelconss, &cutoff) );
12972  }
12973 
12974  if( !cutoff && nchgbds == 0 )
12975  {
12976  /* propgate all other constraints */
12977  for( c = nusefulconss; c < nconss && !cutoff; ++c )
12978  {
12979  SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, &nchgbds, &ndelconss, &cutoff) );
12980  }
12981  }
12982 
12983 #if 0
12984  if( !cutoff && conshdlrdata->dualpresolve && nconss > 1 )
12985  {
12986  SCIP_CALL( propagateAllConss(scip, conshdlrdata, conss, nconss, TRUE, &nchgbds, &cutoff, NULL) );
12987  }
12988 #endif
12989 
12990  if( cutoff )
12991  {
12992  SCIPdebugMessage("detected infeasible\n");
12993  *result = SCIP_CUTOFF;
12994  }
12995  else if( nchgbds > 0 )
12996  {
12997  SCIPdebugMessage("delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
12998  *result = SCIP_REDUCEDDOM;
12999  }
13000  else
13001  *result = SCIP_DIDNOTFIND;
13002 
13003  return SCIP_OKAY;
13004 }
13005 
13006 /** presolving method of constraint handler */
13007 static
13008 SCIP_DECL_CONSPRESOL(consPresolCumulative)
13009 { /*lint --e{715}*/
13010  SCIP_CONSHDLRDATA* conshdlrdata;
13011  SCIP_CONS* cons;
13012  SCIP_Bool cutoff;
13013  SCIP_Bool unbounded;
13014  int oldnfixedvars;
13015  int oldnchgbds;
13016  int oldndelconss;
13017  int oldnaddconss;
13018  int oldnupgdconss;
13019  int oldnchgsides;
13020  int oldnchgcoefs;
13021  int c;
13022 
13023  assert(conshdlr != NULL);
13024  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13025  assert(scip != NULL);
13026  assert(result != NULL);
13027 
13028  SCIPdebugMessage("presolve %d cumulative constraints\n", nconss);
13029 
13030  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13031  assert(conshdlrdata != NULL);
13032 
13033  *result = SCIP_DIDNOTRUN;
13034 
13035  oldnfixedvars = *nfixedvars;
13036  oldnchgbds = *nchgbds;
13037  oldnchgsides = *nchgsides;
13038  oldnchgcoefs = *nchgcoefs;
13039  oldnupgdconss = *nupgdconss;
13040  oldndelconss = *ndelconss;
13041  oldnaddconss = *naddconss;
13042  cutoff = FALSE;
13043  unbounded = FALSE;
13044 
13045  /* process constraints */
13046  for( c = 0; c < nconss && !cutoff; ++c )
13047  {
13048  cons = conss[c];
13049 
13050  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13051  * hmax)
13052  */
13053  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13054 
13055 #if 0
13056  SCIP_CALL( presolveCons(scip, cons, conshdlrdata,
13057  nfixedvars, naggrvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13058 #else
13059  SCIP_CALL( presolveCons(scip, cons, conshdlrdata,
13060  nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13061 #endif
13062 
13063  if( cutoff || unbounded )
13064  break;
13065 
13066  if( SCIPconsIsDeleted(cons) )
13067  continue;
13068 
13069  /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13070  if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13071  {
13072  SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13073  }
13074 
13075  /* strength existing variable bounds using the cumulative condition */
13076  SCIP_CALL( strengthVarbaounds(scip, cons, nchgbds, naddconss) );
13077 
13078  /* propagate cumulative constraint */
13079  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, nchgbds, ndelconss, &cutoff) );
13080  assert(checkDemands(scip, cons) || cutoff);
13081  }
13082 
13083  if( !cutoff && !unbounded && conshdlrdata->dualpresolve && nconss > 1 )
13084  {
13085  SCIP_CALL( propagateAllConss(scip, conshdlrdata, conss, nconss, FALSE,
13086  nfixedvars, &cutoff, NULL) );
13087  }
13088 
13089  /* only perform the detection of variable bounds and disjunctive constraint once */
13090  if( !cutoff && SCIPgetNRuns(scip) == 1 && nrounds == 2
13091  && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive) )
13092  {
13093  /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13094  * propagation
13095  */
13096  SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13097  }
13098 
13099  if( !cutoff && conshdlrdata->presolpairwise )
13100  {
13101  SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13102  }
13103 
13104  SCIPdebugMessage("delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13105  *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13106 
13107  if( cutoff )
13108  *result = SCIP_CUTOFF;
13109  else if( unbounded )
13110  *result = SCIP_UNBOUNDED;
13111  else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13112  || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13113  *result = SCIP_SUCCESS;
13114  else
13115  *result = SCIP_DIDNOTFIND;
13116 
13117  return SCIP_OKAY;
13118 }
13119 
13120 /** propagation conflict resolving method of constraint handler */
13121 static
13122 SCIP_DECL_CONSRESPROP(consRespropCumulative)
13123 { /*lint --e{715}*/
13124  SCIP_CONSHDLRDATA* conshdlrdata;
13125  SCIP_CONSDATA* consdata;
13126 
13127  assert(conshdlr != NULL);
13128  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13129  assert(scip != NULL);
13130  assert(result != NULL);
13131  assert(infervar != NULL);
13132  assert(bdchgidx != NULL);
13133 
13134  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13135  assert(conshdlrdata != NULL);
13136 
13137  /* process constraint */
13138  assert(cons != NULL);
13139 
13140  consdata = SCIPconsGetData(cons);
13141  assert(consdata != NULL);
13142 
13143  SCIPdebugMessage("resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13144  SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13145  SCIPgetHminCumulative(scip, cons), SCIPgetHmaxCumulative(scip, cons));
13146 
13147  SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13148  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13149  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13150 
13151  return SCIP_OKAY;
13152 }
13153 
13154 /** variable rounding lock method of constraint handler */
13155 static
13156 SCIP_DECL_CONSLOCK(consLockCumulative)
13157 { /*lint --e{715}*/
13158  SCIP_CONSDATA* consdata;
13159  SCIP_VAR** vars;
13160  int v;
13161 
13162  SCIPdebugMessage("lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13163 
13164  assert(scip != NULL);
13165  assert(cons != NULL);
13166 
13167  consdata = SCIPconsGetData(cons);
13168  assert(consdata != NULL);
13169 
13170  vars = consdata->vars;
13171  assert(vars != NULL);
13172 
13173  for( v = 0; v < consdata->nvars; ++v )
13174  {
13175  if( consdata->downlocks[v] && consdata->uplocks[v] )
13176  {
13177  /* the integer start variable should not get rounded in both direction */
13178  SCIP_CALL( SCIPaddVarLocks(scip, vars[v], nlockspos + nlocksneg, nlockspos + nlocksneg) );
13179  }
13180  else if( consdata->downlocks[v] )
13181  {
13182  SCIP_CALL( SCIPaddVarLocks(scip, vars[v], nlockspos, nlocksneg) );
13183  }
13184  else if( consdata->uplocks[v] )
13185  {
13186  SCIP_CALL( SCIPaddVarLocks(scip, vars[v], nlocksneg, nlockspos) );
13187  }
13188  }
13189 
13190  return SCIP_OKAY;
13191 }
13192 
13193 
13194 /** constraint display method of constraint handler */
13195 static
13196 SCIP_DECL_CONSPRINT(consPrintCumulative)
13197 { /*lint --e{715}*/
13198  assert(scip != NULL);
13199  assert(conshdlr != NULL);
13200  assert(cons != NULL);
13201 
13202  consdataPrint(scip, SCIPconsGetData(cons), file);
13203 
13204  return SCIP_OKAY;
13205 }
13206 
13207 /** constraint copying method of constraint handler */
13208 static
13209 SCIP_DECL_CONSCOPY(consCopyCumulative)
13210 { /*lint --e{715}*/
13211  SCIP_CONSDATA* sourceconsdata;
13212  SCIP_VAR** sourcevars;
13213  SCIP_VAR** vars;
13214  const char* consname;
13215 
13216  int nvars;
13217  int v;
13218 
13219  sourceconsdata = SCIPconsGetData(sourcecons);
13220  assert(sourceconsdata != NULL);
13221 
13222  /* get variables of the source constraint */
13223  nvars = sourceconsdata->nvars;
13224  sourcevars = sourceconsdata->vars;
13225 
13226  (*valid) = TRUE;
13227 
13228  if( nvars == 0 )
13229  return SCIP_OKAY;
13230 
13231  /* allocate buffer array */
13232  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13233 
13234  for( v = 0; v < nvars && *valid; ++v )
13235  {
13236  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13237  assert(!(*valid) || vars[v] != NULL);
13238  }
13239 
13240  /* only create the target constraint, if all variables could be copied */
13241  if( *valid )
13242  {
13243  if( name != NULL )
13244  consname = name;
13245  else
13246  consname = SCIPconsGetName(sourcecons);
13247 
13248  /* create a copy of the cumulative constraint */
13249  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13250  sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13251  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13252 
13253  /* adjust left side if the time axis if needed */
13254  if( sourceconsdata->hmin > 0 )
13255  {
13256  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13257  }
13258 
13259  /* adjust right side if the time axis if needed */
13260  if( sourceconsdata->hmax < INT_MAX )
13261  {
13262  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13263  }
13264  }
13265 
13266  /* free buffer array */
13267  SCIPfreeBufferArray(scip, &vars);
13268 
13269  return SCIP_OKAY;
13270 }
13271 
13272 
13273 /** constraint parsing method of constraint handler */
13274 static
13275 SCIP_DECL_CONSPARSE(consParseCumulative)
13276 { /*lint --e{715}*/
13277  SCIP_VAR** vars;
13278  SCIP_VAR* var;
13279  SCIP_Real value;
13280  char strvalue[SCIP_MAXSTRLEN];
13281  char* endptr;
13282  int* demands;
13283  int* durations;
13284  int capacity;
13285  int duration;
13286  int demand;
13287  int hmin;
13288  int hmax;
13289  int varssize;
13290  int nvars;
13291 
13292  SCIPdebugMessage("parse <%s> as cumulative constraint\n", str);
13293 
13294  /* cutoff "cumulative" form the constraint string */
13295  SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13296  str = endptr;
13297 
13298  varssize = 100;
13299  nvars = 0;
13300 
13301  /* allocate buffer array for variables */
13302  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13303  SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13304  SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13305 
13306  do
13307  {
13308  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13309 
13310  if( var != NULL )
13311  {
13312  str = endptr;
13313 
13314  SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13315  duration = atoi(strvalue);
13316  str = endptr;
13317 
13318  SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13319  demand = atoi(strvalue);
13320  str = endptr;
13321 
13322  SCIPdebugMessage("parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13323 
13324  vars[nvars] = var;
13325  demands[nvars] = demand;
13326  durations[nvars] = duration;
13327  nvars++;
13328  }
13329  }
13330  while( var != NULL );
13331 
13332  /* parse effective time window */
13333  SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13334  hmin = atoi(strvalue);
13335  str = endptr;
13336 
13337  if( SCIPstrToRealValue(str, &value, &endptr) )
13338  {
13339  hmax = (int)(value);
13340  str = endptr;
13341 
13342  /* parse capacity */
13343  SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13344  str = endptr;
13345  if( SCIPstrToRealValue(str, &value, &endptr) )
13346  {
13347  capacity = (int)value;
13348 
13349  /* create cumulative constraint */
13350  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13351  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13352 
13353  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13354  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13355 
13356  (*success) = TRUE;
13357  }
13358  }
13359 
13360  /* free buffer arrays */
13361  SCIPfreeBufferArray(scip, &durations);
13362  SCIPfreeBufferArray(scip, &demands);
13363  SCIPfreeBufferArray(scip, &vars);
13364 
13365  return SCIP_OKAY;
13366 }
13367 
13368 /** constraint method of constraint handler which returns the variables (if possible) */
13369 static
13370 SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13371 { /*lint --e{715}*/
13372  SCIP_CONSDATA* consdata;
13373 
13374  consdata = SCIPconsGetData(cons);
13375  assert(consdata != NULL);
13376 
13377  if( varssize < consdata->nvars )
13378  (*success) = FALSE;
13379  else
13380  {
13381  assert(vars != NULL);
13382 
13383  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13384  (*success) = TRUE;
13385  }
13386 
13387  return SCIP_OKAY;
13388 }
13389 
13390 /** constraint method of constraint handler which returns the number of variables (if possible) */
13391 static
13392 SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13393 { /*lint --e{715}*/
13394  SCIP_CONSDATA* consdata;
13395 
13396  consdata = SCIPconsGetData(cons);
13397  assert(consdata != NULL);
13398 
13399  (*nvars) = consdata->nvars;
13400  (*success) = TRUE;
13401 
13402  return SCIP_OKAY;
13403 }
13404 
13405 /**@} */
13406 
13407 /**@name Callback methods of event handler
13408  *
13409  * @{
13410  */
13411 
13412 
13413 /** execution method of event handler */
13414 static
13415 SCIP_DECL_EVENTEXEC(eventExecCumulative)
13416 { /*lint --e{715}*/
13417  SCIP_CONSDATA* consdata;
13418 
13419  assert(scip != NULL);
13420  assert(eventhdlr != NULL);
13421  assert(eventdata != NULL);
13422  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13423  assert(event != NULL);
13424 
13425  consdata = (SCIP_CONSDATA*)eventdata;
13426  assert(consdata != NULL);
13427 
13428  /* mark the constraint to be not propagated */
13429  consdata->propagated = FALSE;
13430 
13431  return SCIP_OKAY;
13432 }
13433 
13434 /**@} */
13435 
13436 /**@name Interface methods
13437  *
13438  * @{
13439  */
13440 
13441 /*
13442  * constraint specific interface methods
13443  */
13444 
13445 /** creates the handler for cumulative constraints and includes it in SCIP */
13447  SCIP* scip /**< SCIP data structure */
13448  )
13449 {
13450  SCIP_CONSHDLRDATA* conshdlrdata;
13451  SCIP_CONSHDLR* conshdlr;
13452  SCIP_EVENTHDLR* eventhdlr;
13453 
13454  /* create event handler for bound change events */
13455  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13456 
13457  /* create cumulative constraint handler data */
13458  SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13459 
13460  /* include constraint handler */
13463  consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13464  conshdlrdata) );
13465 
13466  assert(conshdlr != NULL);
13467 
13468  /* set non-fundamental callbacks via specific setter functions */
13469  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13470  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13471 #ifdef SCIP_STATISTIC
13472  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13473 #endif
13474  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13475  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13476  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13477  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13478  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13479  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13480  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13481  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13483  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13484  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropCumulative, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13486  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13487  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13489  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13490 
13491  /* add cumulative constraint handler parameters */
13493  "constraints/"CONSHDLR_NAME"/ttinfer",
13494  "should time-table (core-times) propagator be used to infer bounds?",
13495  &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13497  "constraints/"CONSHDLR_NAME"/efcheck",
13498  "should edge-finding be used to detect an overload?",
13499  &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13501  "constraints/"CONSHDLR_NAME"/efinfer",
13502  "should edge-finding be used to infer bounds?",
13503  &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13505  "constraints/"CONSHDLR_NAME"/useadjustedjobs", "should edge-finding be executed?",
13506  &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13508  "constraints/"CONSHDLR_NAME"/ttefcheck",
13509  "should time-table edge-finding be used to detect an overload?",
13510  &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13512  "constraints/"CONSHDLR_NAME"/ttefinfer",
13513  "should time-table edge-finding be used to infer bounds?",
13514  &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13515 
13517  "constraints/"CONSHDLR_NAME"/usebinvars", "should the binary representation be used?",
13518  &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13520  "constraints/"CONSHDLR_NAME"/localcuts", "should cuts be added only locally?",
13521  &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13523  "constraints/"CONSHDLR_NAME"/usecovercuts", "should covering cuts be added every node?",
13524  &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13526  "constraints/"CONSHDLR_NAME"/cutsasconss",
13527  "should the cumulative constraint create cuts as knapsack constraints?",
13528  &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13530  "constraints/"CONSHDLR_NAME"/sepaold",
13531  "shall old sepa algo be applied?",
13532  &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13533 
13535  "constraints/"CONSHDLR_NAME"/fillbranchcands", "should branching candidates be added to storage?",
13536  &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13537 
13538  /* presolving parameters */
13540  "constraints/"CONSHDLR_NAME"/dualpresolve", "should dual presolving be applied?",
13541  &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13543  "constraints/"CONSHDLR_NAME"/coeftightening", "should coefficient tightening be applied?",
13544  &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13546  "constraints/"CONSHDLR_NAME"/normalize", "should demands and capacity be normalized?",
13547  &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13549  "constraints/"CONSHDLR_NAME"/presolpairwise",
13550  "should pairwise constraint comparison be performed in presolving?",
13551  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13553  "constraints/"CONSHDLR_NAME"/disjunctive", "extract disjunctive constraints?",
13554  &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13555 
13557  "constraints/"CONSHDLR_NAME"/maxnodes",
13558  "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13559  &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13561  "constraints/"CONSHDLR_NAME"/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13562  &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13564  "constraints/"CONSHDLR_NAME"/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13565  &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13566 
13567  /* conflict analysis parameters */
13569  "constraints/"CONSHDLR_NAME"/usebdwidening", "should bound widening be used during the conflict analysis?",
13570  &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13571 
13572  return SCIP_OKAY;
13573 }
13574 
13575 /** creates and captures a cumulative constraint */
13577  SCIP* scip, /**< SCIP data structure */
13578  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13579  const char* name, /**< name of constraint */
13580  int nvars, /**< number of variables (jobs) */
13581  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13582  int* durations, /**< array containing corresponding durations */
13583  int* demands, /**< array containing corresponding demands */
13584  int capacity, /**< available cumulative capacity */
13585  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13586  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13587  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13588  * Usually set to TRUE. */
13589  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13590  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13591  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13592  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13593  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13594  * Usually set to TRUE. */
13595  SCIP_Bool local, /**< is constraint only valid locally?
13596  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13597  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13598  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13599  * adds coefficients to this constraint. */
13600  SCIP_Bool dynamic, /**< is constraint subject to aging?
13601  * Usually set to FALSE. Set to TRUE for own cuts which
13602  * are seperated as constraints. */
13603  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13604  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13605  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13606  * if it may be moved to a more global node?
13607  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13608  )
13609 {
13610  SCIP_CONSHDLR* conshdlr;
13611  SCIP_CONSDATA* consdata;
13612 
13613  assert(scip != NULL);
13614 
13615  /* find the cumulative constraint handler */
13616  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13617  if( conshdlr == NULL )
13618  {
13619  SCIPerrorMessage(""CONSHDLR_NAME" constraint handler not found\n");
13620  return SCIP_PLUGINNOTFOUND;
13621  }
13622 
13623  SCIPdebugMessage("create cumulative constraint <%s> with %d jobs\n", name, nvars);
13624 
13625  /* create constraint data */
13626  SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13627 
13628  /* create constraint */
13629  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13630  initial, separate, enforce, check, propagate,
13631  local, modifiable, dynamic, removable, stickingatnode) );
13632 
13633 
13634  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13635  {
13636  SCIP_CONSHDLRDATA* conshdlrdata;
13637 
13638  /* get event handler */
13639  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13640  assert(conshdlrdata != NULL);
13641  assert(conshdlrdata->eventhdlr != NULL);
13642 
13643  /* catch bound change events of variables */
13644  SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13645  }
13646 
13647  return SCIP_OKAY;
13648 }
13649 
13650 /** creates and captures a cumulative constraint
13651  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13652  * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13653  *
13654  * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13655  *
13656  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13657  */
13659  SCIP* scip, /**< SCIP data structure */
13660  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13661  const char* name, /**< name of constraint */
13662  int nvars, /**< number of variables (jobs) */
13663  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13664  int* durations, /**< array containing corresponding durations */
13665  int* demands, /**< array containing corresponding demands */
13666  int capacity /**< available cumulative capacity */
13667  )
13668 {
13669  assert(scip != NULL);
13670 
13671  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13672  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13673 
13674  return SCIP_OKAY;
13675 }
13676 
13677 /** set the left bound of the time axis to be considered (including hmin) */
13679  SCIP* scip, /**< SCIP data structure */
13680  SCIP_CONS* cons, /**< constraint data */
13681  int hmin /**< left bound of time axis to be considered */
13682  )
13683 {
13684  SCIP_CONSDATA* consdata;
13685  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13686  {
13687  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13688  return SCIP_INVALIDCALL;
13689  }
13690 
13691  consdata = SCIPconsGetData(cons);
13692  assert(consdata != NULL);
13693  assert(hmin >= 0);
13694  assert(hmin <= consdata->hmax);
13695 
13696  consdata->hmin = hmin;
13697 
13698  return SCIP_OKAY;
13699 }
13700 
13701 /** returns the left bound of the time axis to be considered */
13703  SCIP* scip, /**< SCIP data structure */
13704  SCIP_CONS* cons /**< constraint */
13705  )
13706 {
13707  SCIP_CONSDATA* consdata;
13708  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13709  {
13710  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13711  SCIPABORT();
13712  return 0; /*lint !e527*/
13713  }
13714 
13715  consdata = SCIPconsGetData(cons);
13716  assert(consdata != NULL);
13717 
13718  return consdata->hmin;
13719 }
13720 
13721 /** set the right bound of the time axis to be considered (not including hmax) */
13723  SCIP* scip, /**< SCIP data structure */
13724  SCIP_CONS* cons, /**< constraint data */
13725  int hmax /**< right bound of time axis to be considered */
13726  )
13727 {
13728  SCIP_CONSDATA* consdata;
13729  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13730  {
13731  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13732  SCIPABORT();
13733  return SCIP_INVALIDCALL; /*lint !e527*/
13734  }
13735 
13736  consdata = SCIPconsGetData(cons);
13737  assert(consdata != NULL);
13738  assert(hmax >= consdata->hmin);
13739 
13740  consdata->hmax = hmax;
13741 
13742  return SCIP_OKAY;
13743 }
13744 
13745 /** returns the right bound of the time axis to be considered */
13747  SCIP* scip, /**< SCIP data structure */
13748  SCIP_CONS* cons /**< constraint */
13749  )
13750 {
13751  SCIP_CONSDATA* consdata;
13752  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13753  {
13754  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13755  SCIPABORT();
13756  return 0; /*lint !e527*/
13757  }
13758 
13759  consdata = SCIPconsGetData(cons);
13760  assert(consdata != NULL);
13761 
13762  return consdata->hmax;
13763 }
13764 
13765 /** returns the activities of the cumulative constraint */
13767  SCIP* scip, /**< SCIP data structure */
13768  SCIP_CONS* cons /**< constraint data */
13769  )
13770 {
13771  SCIP_CONSDATA* consdata;
13772 
13773  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13774  {
13775  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13776  SCIPABORT();
13777  return NULL; /*lint !e527*/
13778  }
13779 
13780  consdata = SCIPconsGetData(cons);
13781  assert(consdata != NULL);
13782 
13783  return consdata->vars;
13784 }
13785 
13786 /** returns the activities of the cumulative constraint */
13788  SCIP* scip, /**< SCIP data structure */
13789  SCIP_CONS* cons /**< constraint data */
13790  )
13791 {
13792  SCIP_CONSDATA* consdata;
13793 
13794  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13795  {
13796  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13797  SCIPABORT();
13798  return -1; /*lint !e527*/
13799  }
13800 
13801  consdata = SCIPconsGetData(cons);
13802  assert(consdata != NULL);
13803 
13804  return consdata->nvars;
13805 }
13806 
13807 /** returns the capacity of the cumulative constraint */
13809  SCIP* scip, /**< SCIP data structure */
13810  SCIP_CONS* cons /**< constraint data */
13811  )
13812 {
13813  SCIP_CONSDATA* consdata;
13814 
13815  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13816  {
13817  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13818  SCIPABORT();
13819  return -1; /*lint !e527*/
13820  }
13821 
13822  consdata = SCIPconsGetData(cons);
13823  assert(consdata != NULL);
13824 
13825  return consdata->capacity;
13826 }
13827 
13828 /** returns the durations of the cumulative constraint */
13830  SCIP* scip, /**< SCIP data structure */
13831  SCIP_CONS* cons /**< constraint data */
13832  )
13833 {
13834  SCIP_CONSDATA* consdata;
13835 
13836  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13837  {
13838  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13839  SCIPABORT();
13840  return NULL; /*lint !e527*/
13841  }
13842 
13843  consdata = SCIPconsGetData(cons);
13844  assert(consdata != NULL);
13845 
13846  return consdata->durations;
13847 }
13848 
13849 /** returns the demands of the cumulative constraint */
13851  SCIP* scip, /**< SCIP data structure */
13852  SCIP_CONS* cons /**< constraint data */
13853  )
13854 {
13855  SCIP_CONSDATA* consdata;
13856 
13857  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13858  {
13859  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13860  SCIPABORT();
13861  return NULL; /*lint !e527*/
13862  }
13863 
13864  consdata = SCIPconsGetData(cons);
13865  assert(consdata != NULL);
13866 
13867  return consdata->demands;
13868 }
13869 
13870 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
13871  * given solution is satisfied
13872  */
13874  SCIP* scip, /**< SCIP data structure */
13875  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
13876  int nvars, /**< number of variables (jobs) */
13877  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13878  int* durations, /**< array containing corresponding durations */
13879  int* demands, /**< array containing corresponding demands */
13880  int capacity, /**< available cumulative capacity */
13881  int hmin, /**< left bound of time axis to be considered (including hmin) */
13882  int hmax, /**< right bound of time axis to be considered (not including hmax) */
13883  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
13884  SCIP_CONS* cons, /**< constraint which is checked */
13885  SCIP_Bool printreason /**< should the reason for the violation be printed? */
13886  )
13887 {
13888  assert(scip != NULL);
13889  assert(violated != NULL);
13890 
13891  SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
13892  violated, cons, printreason) );
13893 
13894  return SCIP_OKAY;
13895 }
13896 
13897 /** normalize cumulative condition */
13899  SCIP* scip, /**< SCIP data structure */
13900  int nvars, /**< number of start time variables (activities) */
13901  SCIP_VAR** vars, /**< array of start time variables */
13902  int* durations, /**< array of durations */
13903  int* demands, /**< array of demands */
13904  int* capacity, /**< pointer to store the changed cumulative capacity */
13905  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
13906  int* nchgsides /**< pointer to count number of side changes */
13907  )
13908 {
13909  SCIP_CALL( normalizeCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
13910  nchgcoefs, nchgsides) );
13911 
13912  return SCIP_OKAY;
13913 }
13914 
13915 /** searches for a time point within the cumulative condition were the cumulative condition can be split */
13917  SCIP* scip, /**< SCIP data structure */
13918  int nvars, /**< number of variables (jobs) */
13919  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13920  int* durations, /**< array containing corresponding durations */
13921  int* demands, /**< array containing corresponding demands */
13922  int capacity, /**< available cumulative capacity */
13923  int* hmin, /**< pointer to store the left bound of the effective horizon */
13924  int* hmax, /**< pointer to store the right bound of the effective horizon */
13925  int* split /**< point were the cumulative condition can be split */
13926  )
13927 {
13928  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
13929  hmin, hmax, split) );
13930 
13931  return SCIP_OKAY;
13932 }
13933 
13934 /** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
13936  SCIP* scip, /**< SCIP data structure */
13937  int nvars, /**< number of start time variables (activities) */
13938  SCIP_VAR** vars, /**< array of start time variables */
13939  int* durations, /**< array of durations */
13940  int hmin, /**< left bound of time axis to be considered */
13941  int hmax, /**< right bound of time axis to be considered (not including hmax) */
13942  SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
13943  SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
13944  SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
13945  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
13946  int* nfixedvars, /**< pointer to store the number of fixed variables */
13947  int* nchgsides, /**< pointer to store the number of changed sides */
13948  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
13949  )
13950 {
13951  if( nvars <= 1 )
13952  return SCIP_OKAY;
13953 
13954  /* presolve constraint form the earlier start time point of view */
13955  SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
13956  irrelevants, nfixedvars, nchgsides, cutoff) );
13957 
13958  /* presolve constraint form the latest completion time point of view */
13959  SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
13960  irrelevants, nfixedvars, nchgsides, cutoff) );
13961 
13962  return SCIP_OKAY;
13963 }
13964 
13965 /** propagate the given cumulative condition */
13967  SCIP* scip, /**< SCIP data structure */
13968  int nvars, /**< number of variables (jobs) */
13969  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13970  int* durations, /**< array containing corresponding durations */
13971  int* demands, /**< array containing corresponding demands */
13972  int capacity, /**< available cumulative capacity */
13973  int hmin, /**< left bound of time axis to be considered (including hmin) */
13974  int hmax, /**< right bound of time axis to be considered (not including hmax) */
13975  SCIP_CONS* cons, /**< constraint which gets propagated */
13976  int* nchgbds, /**< pointer to store the number of variable bound changes */
13977  SCIP_Bool* initialized, /**< was conflict analysis initialized */
13978  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
13979  SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
13980  )
13981 {
13982  SCIP_CONSHDLR* conshdlr;
13983  SCIP_CONSHDLRDATA* conshdlrdata;
13984  SCIP_Bool redundant;
13985 
13986  assert(scip != NULL);
13987  assert(cons != NULL);
13988  assert(initialized != NULL);
13989  assert(*initialized == FALSE);
13990  assert(cutoff != NULL);
13991  assert(*cutoff == FALSE);
13992 
13993  /* find the cumulative constraint handler */
13994  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13995  if( conshdlr == NULL )
13996  {
13997  SCIPerrorMessage(""CONSHDLR_NAME" constraint handler not found\n");
13998  return SCIP_PLUGINNOTFOUND;
13999  }
14000 
14001  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14002  assert(conshdlrdata != NULL);
14003 
14004  redundant = FALSE;
14005 
14006  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata,
14007  nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14008  nchgbds, &redundant, initialized, explanation, cutoff) );
14009 
14010  return SCIP_OKAY;
14011 }
14012 
14013 /** resolve propagation w.r.t. the cumulative condition */
14015  SCIP* scip, /**< SCIP data structure */
14016  int nvars, /**< number of start time variables (activities) */
14017  SCIP_VAR** vars, /**< array of start time variables */
14018  int* durations, /**< array of durations */
14019  int* demands, /**< array of demands */
14020  int capacity, /**< cumulative capacity */
14021  int hmin, /**< left bound of time axis to be considered (including hmin) */
14022  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14023  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14024  int inferinfo, /**< the user information */
14025  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14026  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14027  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14028  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14029  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14030  )
14031 {
14032  SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14033  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14034 
14035  return SCIP_OKAY;
14036 }
14037 
14038 /** this method visualizes the cumulative structure in GML format */
14040  SCIP* scip, /**< SCIP data structure */
14041  SCIP_CONS* cons /**< cumulative constraint */
14042  )
14043 {
14044  SCIP_CONSDATA* consdata;
14045  SCIP_HASHTABLE* vars;
14046  FILE* file;
14047  SCIP_VAR* var;
14048  char filename[SCIP_MAXSTRLEN];
14049  int nvars;
14050  int v;
14051 
14052  /* open file */
14053  (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14054  file = fopen(filename, "w");
14055 
14056  /* check if the file was open */
14057  if( file == NULL )
14058  {
14059  SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14060  SCIPprintSysError(filename);
14061  return SCIP_FILECREATEERROR;
14062  }
14063 
14064  consdata = SCIPconsGetData(cons);
14065  assert(consdata != NULL);
14066 
14067  nvars = consdata->nvars;
14068 
14070  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
14071 
14072  /* create opening of the GML format */
14073  SCIPgmlWriteOpening(file, TRUE);
14074 
14075  for( v = 0; v < nvars; ++v )
14076  {
14077  char color[SCIP_MAXSTRLEN];
14078 
14079  var = consdata->vars[v];
14080  assert(var != NULL);
14081 
14082  SCIP_CALL( SCIPhashtableInsert(vars, (void*)var) );
14083 
14084  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14085  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14086  else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14087  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14088  else
14089  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14090 
14091  SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14092  }
14093 
14094  for( v = 0; v < nvars; ++v )
14095  {
14096  SCIP_VAR** vbdvars;
14097  int nvbdvars;
14098  int b;
14099 
14100  var = consdata->vars[v];
14101  assert(var != NULL);
14102 
14103  vbdvars = SCIPvarGetVlbVars(var);
14104  nvbdvars = SCIPvarGetNVlbs(var);
14105 
14106  for( b = 0; b < nvbdvars; ++b )
14107  {
14108  if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14109  {
14110  SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14111  }
14112  }
14113 
14114 #if 0
14115  vbdvars = SCIPvarGetVubVars(var);
14116  nvbdvars = SCIPvarGetNVubs(var);
14117 
14118  for( b = 0; b < nvbdvars; ++b )
14119  {
14120  if( SCIPhashtableExists(vars, vbdvars[b]) )
14121  {
14122  SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14123  }
14124  }
14125 #endif
14126  }
14127 
14128  /* create closing of the GML format */
14129  SCIPgmlWriteClosing(file);
14130 
14131  /* close file */
14132  fclose(file);
14133 
14134  SCIPhashtableFree(&vars);
14135 
14136  return SCIP_OKAY;
14137 }
14138 
14139 /** sets method to solve an individual cumulative condition */
14141  SCIP* scip, /**< SCIP data structure */
14142  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14143  )
14144 {
14145  SCIP_CONSHDLR* conshdlr;
14146  SCIP_CONSHDLRDATA* conshdlrdata;
14147 
14148  /* find the cumulative constraint handler */
14149  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14150  if( conshdlr == NULL )
14151  {
14152  SCIPerrorMessage(""CONSHDLR_NAME" constraint handler not found\n");
14153  return SCIP_PLUGINNOTFOUND;
14154  }
14155 
14156  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14157  assert(conshdlrdata != NULL);
14158 
14159  conshdlrdata->solveCumulative = solveCumulative;
14160 
14161  return SCIP_OKAY;
14162 }
14163 
14164 /** solves given cumulative condition as independent sub problem
14165  *
14166  * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14167  * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14168  * solver was interrupted.
14169  */
14171  SCIP* scip, /**< SCIP data structure */
14172  int njobs, /**< number of jobs (activities) */
14173  SCIP_Real* ests, /**< array with the earlier start time for each job */
14174  SCIP_Real* lsts, /**< array with the latest start time for each job */
14175  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14176  int* durations, /**< array of durations */
14177  int* demands, /**< array of demands */
14178  int capacity, /**< cumulative capacity */
14179  int hmin, /**< left bound of time axis to be considered (including hmin) */
14180  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14181  SCIP_Real timelimit, /**< time limit for solving in seconds */
14182  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14183  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14184  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14185  SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14186  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14187  SCIP_Bool* error /**< pointer to store if an error occurred */
14188  )
14189 {
14190  SCIP_CONSHDLR* conshdlr;
14191  SCIP_CONSHDLRDATA* conshdlrdata;
14192 
14193  (*solved) = TRUE;
14194  (*infeasible) = FALSE;
14195  (*unbounded) = FALSE;
14196  (*error) = FALSE;
14197 
14198  if( njobs == 0 )
14199  return SCIP_OKAY;
14200 
14201  /* find the cumulative constraint handler */
14202  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14203  if( conshdlr == NULL )
14204  {
14205  SCIPerrorMessage(""CONSHDLR_NAME" constraint handler not found\n");
14206  (*error) = TRUE;
14207  return SCIP_PLUGINNOTFOUND;
14208  }
14209 
14210  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14211  assert(conshdlrdata != NULL);
14212 
14213  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14214  if( timelimit > 0.0 && memorylimit > 10 )
14215  {
14216  SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14217  hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14218  }
14219 
14220  return SCIP_OKAY;
14221 }
14222 
14223 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14224  * completion time
14225  */
14227  SCIP* scip, /**< SCIP data structure */
14228  SCIP_PROFILE* profile, /**< resource profile */
14229  int nvars, /**< number of variables (jobs) */
14230  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14231  int* durations, /**< array containing corresponding durations */
14232  int* demands /**< array containing corresponding demands */
14233  )
14234 {
14235  SCIP_VAR* var;
14236  SCIP_HASHMAP* addedvars;
14237  int* copydemands;
14238  int* perm;
14239  int duration;
14240  int impliedest;
14241  int est;
14242  int impliedlct;
14243  int lct;
14244  int v;
14245 
14246  /* create hash map for variables which are added, mapping to their duration */
14247  SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), SCIPcalcHashtableSize(nvars)) );
14248 
14249  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14250  SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14251 
14252  /* sort variables w.r.t. job demands */
14253  for( v = 0; v < nvars; ++v )
14254  {
14255  copydemands[v] = demands[v];
14256  perm[v] = v;
14257  }
14258  SCIPsortDownIntInt(copydemands, perm, nvars);
14259 
14260  /* add each job with its earliest start and latest completion time into the resource profile */
14261  for( v = 0; v < nvars; ++v )
14262  {
14263  int idx;
14264 
14265  idx = perm[v];
14266  assert(idx >= 0 && idx < nvars);
14267 
14268  var = vars[idx];
14269  assert(var != NULL);
14270 
14271  duration = durations[idx];
14272  assert(duration > 0);
14273 
14274  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
14275  SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14276 
14277  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14278  SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14279 
14280  if( impliedest < impliedlct )
14281  {
14282  SCIP_Bool infeasible;
14283  int pos;
14284 
14285  SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14286  assert(!infeasible);
14287  assert(pos == -1);
14288  }
14289 
14290  if( est == impliedest && lct == impliedlct )
14291  {
14292  SCIP_CALL( SCIPhashmapInsert(addedvars, (void*)var, (void*)(size_t)duration) );
14293  }
14294  }
14295 
14296  SCIPfreeBufferArray(scip, &copydemands);
14297  SCIPfreeBufferArray(scip, &perm);
14298 
14299  SCIPhashmapFree(&addedvars);
14300 
14301  return SCIP_OKAY;
14302 }
14303 
14304 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */
14305 int SCIPcomputeHmin(
14306  SCIP* scip, /**< SCIP data structure */
14307  SCIP_PROFILE* profile, /**< worst case resource profile */
14308  int capacity /**< capacity to check */
14309  )
14310 {
14311  int* timepoints;
14312  int* loads;
14313  int ntimepoints;
14314  int t;
14315 
14316  ntimepoints = SCIPprofileGetNTimepoints(profile);
14317  timepoints = SCIPprofileGetTimepoints(profile);
14318  loads = SCIPprofileGetLoads(profile);
14319 
14320  /* find first time point which potentially violates the capacity restriction */
14321  for( t = 0; t < ntimepoints - 1; ++t )
14322  {
14323  /* check if the time point exceed w.r.t. worst case profile the capacity */
14324  if( loads[t] > capacity )
14325  {
14326  assert(t == 0 || loads[t-1] <= capacity);
14327  return timepoints[t];
14328  }
14329  }
14330 
14331  return INT_MAX;
14332 }
14333 
14334 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity is satisfied for sure */
14335 int SCIPcomputeHmax(
14336  SCIP* scip, /**< SCIP data structure */
14337  SCIP_PROFILE* profile, /**< worst case profile */
14338  int capacity /**< capacity to check */
14339  )
14340 {
14341  int* timepoints;
14342  int* loads;
14343  int ntimepoints;
14344  int t;
14345 
14346  ntimepoints = SCIPprofileGetNTimepoints(profile);
14347  timepoints = SCIPprofileGetTimepoints(profile);
14348  loads = SCIPprofileGetLoads(profile);
14349 
14350  /* find last time point which potentially violates the capacity restriction */
14351  for( t = ntimepoints - 1; t >= 0; --t )
14352  {
14353  /* check if at time point t the worst case resource profile exceeds the capacity */
14354  if( loads[t] > capacity )
14355  {
14356  assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14357  return timepoints[t+1];
14358  }
14359  }
14360 
14361  return INT_MIN;
14362 }
14363 
14364 /**@} */
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:51
static SCIP_RETCODE consdataCatchEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip.c:20784
static SCIP_RETCODE strengthVarbaounds(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *naddconss)
SCIP_RETCODE SCIPbtnodeCreate(SCIP_BT *tree, SCIP_BTNODE **node, void *dataptr)
Definition: misc.c:6151
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38254
#define CONSHDLR_SEPAPRIORITY
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
SCIP_RETCODE SCIPsetSolveCumulative(SCIP *scip, SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)))
struct InferInfo INFERINFO
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:38397
void SCIPbtnodeFree(SCIP_BT *tree, SCIP_BTNODE **node)
Definition: misc.c:6215
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip.c:25984
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:10071
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:5600
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:5332
static SCIP_RETCODE propagateAllConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *nfixedvars, SCIP_Bool *cutoff, SCIP_Bool *branched)
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:23286
static SCIP_DECL_CONSCOPY(consCopyCumulative)
enum TCLIQUE_Status TCLIQUE_STATUS
Definition: tclique.h:57
static TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
#define DEFAULT_TTINFER
#define CONSHDLR_PROPFREQ
static int computeEnergyContribution(SCIP_BTNODE *node)
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:15788
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)
static SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip.c:897
static SCIP_RETCODE consdataDropAllEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static PROPRULE inferInfoGetProprule(INFERINFO inferinfo)
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)
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition: scip.c:20892
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_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:38360
int SCIPconvertRealToInt(SCIP *scip, SCIP_Real real)
Definition: scip.c:39272
SCIP_RETCODE SCIPprofileDeleteCore(SCIP_PROFILE *profile, int left, int right, int demand)
Definition: misc.c:4998
static SCIP_RETCODE computeMinDistance(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int source, int sink, int *naddconss)
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip.c:13922
void * SCIPbtnodeGetData(SCIP_BTNODE *node)
Definition: misc.c:6260
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:1374
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:19206
struct TCLIQUE_Graph TCLIQUE_GRAPH
Definition: tclique.h:38
static INFERINFO intToInferInfo(int i)
static void consdataPrint(SCIP *scip, SCIP_CONSDATA *consdata, FILE *file)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:9751
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:10913
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)
SCIP_Bool SCIPexistsConsLinking(SCIP *scip, SCIP_VAR *intvar)
static SCIP_RETCODE createCoverCutsTimepoint(SCIP *scip, SCIP_CONS *cons, int *startvalues, int time)
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip.c:13986
static SCIP_RETCODE createCapacityRestrictionIntvars(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower)
SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
Definition: scip.c:3959
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip.c:10026
static void addEndingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *endtimes, int *endindices, int *freecapacity, int *idx, int nvars)
#define SCIP_MAXSTRLEN
Definition: def.h:196
#define DEFAULT_MAXNODES
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip.c:5378
SCIP_RETCODE SCIPtransformConss(SCIP *scip, int nconss, SCIP_CONS **conss, SCIP_CONS **transconss)
Definition: scip.c:23100
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip.c:4990
void SCIPgmlWriteArc(FILE *file, unsigned int source, unsigned int target, const char *label, const char *color)
Definition: misc.c:244
SCIP_RETCODE SCIPpresolveCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
static 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)
#define NULL
Definition: lpi_spx.cpp:129
static SCIP_RETCODE analyzeEnergyRequirement(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int begin, int end, SCIP_VAR *infervar, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation)
static void initializeLocks(SCIP_CONSDATA *consdata, SCIP_Bool locked)
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:16426
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1111
#define CONSHDLR_NAME
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:16636
#define CONSHDLR_PROP_TIMING
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:7786
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:16574
static SCIP_RETCODE createDisjuctiveCons(SCIP *scip, SCIP_CONS *cons, int *naddconss)
#define CONSHDLR_CHECKPRIORITY
static int inferInfoGetData1(INFERINFO inferinfo)
static SCIP_RETCODE solveIndependentCons(SCIP *scip, SCIP_CONS *cons, SCIP_Longint maxnodes, int *nchgbds, int *nfixedvars, int *ndelconss, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:7618
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:5078
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:16380
static void updateKeyOnTrace(SCIP_BTNODE *node, SCIP_Real key)
void SCIPgmlWriteNode(FILE *file, unsigned int id, const char *label, const char *nodetype, const char *fillcolor, const char *bordercolor)
Definition: misc.c:102
static SCIP_RETCODE presolveConsEst(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
int SCIPprofileGetTime(SCIP_PROFILE *profile, int pos)
Definition: misc.c:4795
static SCIP_RETCODE computePeak(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *timepoint)
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:16604
int * SCIPgetDemandsCumulative(SCIP *scip, SCIP_CONS *cons)
static void transitiveClosure(SCIP_Bool **adjmatrix, int *ninarcs, int *noutarcs, int nnodes)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
Definition: scip.c:22044
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip.c:15670
void SCIPgmlWriteClosing(FILE *file)
Definition: misc.c:304
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:5562
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:7354
void SCIPbtnodeSetRightchild(SCIP_BTNODE *node, SCIP_BTNODE *right)
Definition: misc.c:6421
static SCIP_Bool isConsIndependently(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE applyAlternativeBoundsFixing(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, int *nfixedvars, SCIP_Bool *cutoff)
static SCIP_DECL_SORTPTRCOMP(compNodeEst)
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition: scip.c:14066
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:7846
#define FALSE
Definition: def.h:52
static SCIP_RETCODE collectIntVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***activevars, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower, int *lhs)
static SCIP_RETCODE fixIntegerVariableLb(SCIP *scip, SCIP_VAR *var, SCIP_Bool downlock, int *nfixedvars)
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:1864
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip.c:37596
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip.c:3869
static SCIP_RETCODE consdataFreeRows(SCIP *scip, SCIP_CONSDATA **consdata)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:7209
static SCIP_RETCODE checkOverloadViaThetaTree(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool propest, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:7579
#define TRUE
Definition: def.h:51
SCIP_RETCODE SCIPvisualizeConsCumulative(SCIP *scip, SCIP_CONS *cons)
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:7577
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip.c:30273
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
int SCIPgetNVarsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
static void subtractStartingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *starttimes, int *startindices, int *freecapacity, int *idx, int nvars)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:5539
static SCIP_RETCODE presolveConsEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff)
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 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)
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition: scip.c:3914
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_Bool delaypresol)
Definition: scip.c:5271
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 getNodeIdx(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_VAR *var, int *idx)
static void conshdlrdataFree(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata)
void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:38779
#define DEFAULT_LOCALCUTS
#define SCIPfreeBuffer(scip, ptr)
Definition: scip.h:19219
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:19185
SCIP_Real SCIPvarGetLbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:15141
static SCIP_RETCODE deleteLambdaLeaf(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
SCIP_RETCODE SCIPprofileInsertCore(SCIP_PROFILE *profile, int left, int right, int demand, int *pos, SCIP_Bool *infeasible)
Definition: misc.c:4968
SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3442
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:31775
#define CONSHDLR_DELAYPROP
static SCIP_RETCODE separateCoverCutsCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:19214
#define DEFAULT_USEBINVARS
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:16227
static TCLIQUE_ISEDGE(tcliqueIsedgeClique)
tclique user interface
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:22618
static SCIP_RETCODE createCoreProfile(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:1923
#define DEFAULT_COEFTIGHTENING
static SCIP_RETCODE createNodedata(SCIP *scip, SCIP_NODEDATA **nodedata)
#define SCIP_LONGINT_MAX
Definition: def.h:108
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING timingmask)
Definition: scip.c:5036
SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_setppc.c:9067
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:7776
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:7716
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:23934
SCIP_RETCODE SCIPsplitCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
SCIP_RETCODE SCIPaddCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:28256
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:22651
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
int SCIPgetCapacityCumulative(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_TTEFCHECK
static void createSelectedSortedEventpointsSol(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *starttimes, int *endtimes, int *startindices, int *endindices, int *nvars, SCIP_Bool lower)
static SCIP_DECL_CONSINITLP(consInitlpCumulative)
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:19215
int SCIPprofileGetLoad(SCIP_PROFILE *profile, int pos)
Definition: misc.c:4807
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11177
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
Definition: scip.c:38815
static SCIP_DECL_CONSPRESOL(consPresolCumulative)
SCIP_RETCODE SCIPcreateWorstCaseProfile(SCIP *scip, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands)
#define DEFAULT_NORMALIZE
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.c:5103
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:7706
SCIP_Bool SCIPbtnodeIsRoot(SCIP_BTNODE *node)
Definition: misc.c:6320
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)
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 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_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:18686
#define CONSHDLR_DELAYPRESOL
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:1287
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 SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
Definition: scip.c:22424
static void freeTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
#define CONSHDLR_DESC
static void createSortedEventpointsSol(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices)
static SCIP_RETCODE conshdlrdataCreate(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3388
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:15907
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:1966
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip.c:14405
SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
Definition: scip.c:8510
int SCIPcomputeHmax(SCIP *scip, SCIP_PROFILE *profile, int capacity)
static SCIP_RETCODE propagateCumulativeCondition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, 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_RETCODE updateEnvelop(SCIP *scip, SCIP_BTNODE *node)
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:3893
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)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:33378
int SCIPcomputeHmin(SCIP *scip, SCIP_PROFILE *profile, int capacity)
static SCIP_RETCODE getHighestCapacityUsage(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, int *bestcapacity)
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 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)
Constraint handler for knapsack constraints of the form , x binary and .
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip)
Definition: scip.c:22066
int SCIPgetNConss(SCIP *scip)
Definition: scip.c:11109
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38273
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:15930
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip.c:1690
int * SCIPgetValsLinking(SCIP *scip, SCIP_CONS *cons)
#define CONSHDLR_EAGERFREQ
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:19183
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)
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:16616
static int inferInfoGetData2(INFERINFO inferinfo)
#define EVENTHDLR_NAME
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:38421
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)
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:7816
#define SCIPallocMemory(scip, ptr)
Definition: scip.h:19159
static SCIP_DECL_CONSLOCK(consLockCumulative)
SCIP_BTNODE * SCIPbtnodeGetParent(SCIP_BTNODE *node)
Definition: misc.c:6270
#define SCIPallocBuffer(scip, ptr)
Definition: scip.h:19213
static SCIP_RETCODE tightenUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int lst, int lct, int begin, int end, int energy, int *bestub, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
#define SCIPerrorMessage
Definition: pub_message.h:45
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:19221
static SCIP_RETCODE enforceSolution(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool branch, SCIP_RESULT *result)
#define SCIPdebugPrintf
Definition: pub_message.h:80
static SCIP_RETCODE projectVbd(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph)
static SCIP_RETCODE createTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:17713
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:19207
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip.c:23000
void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:38767
void SCIPbtnodeSetLeftchild(SCIP_BTNODE *node, SCIP_BTNODE *left)
Definition: misc.c:6407
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)
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:3873
int SCIPcalcHashtableSize(int minsize)
Definition: misc.c:964
SCIP_Real SCIPvarGetUbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:15233
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:15989
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38292
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:25827
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:37940
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
void SCIPstrCopySection(const char *str, char startchar, char endchar, char *token, int size, char **endptr)
Definition: misc.c:7680
static void traceLambdaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:7557
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:15999
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)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38648
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:18848
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:146
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:1882
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:5247
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:19189
SCIP_RETCODE SCIPsetHminCumulative(SCIP *scip, SCIP_CONS *cons, int hmin)
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, int *nchgbds, int *ndelconss, SCIP_Bool *cutoff)
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)
int SCIPvarGetNLocksUp(SCIP_VAR *var)
Definition: var.c:3214
void tcliqueMaxClique(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, TCLIQUE_WEIGHT maxfirstnodeweight, TCLIQUE_WEIGHT minweight, int maxntreenodes, int backtrackfreq, int maxnzeroextensions, int fixednode, int *ntreenodes, TCLIQUE_STATUS *status)
#define CONSHDLR_MAXPREROUNDS
static SCIP_RETCODE createCoverCuts(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:38349
static int computeTotalEnergy(int *durations, int *demands, int njobs)
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_CALL(x)
Definition: def.h:258
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
static SCIP_RETCODE propagateLbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, int *newlbs, int *newubs, int *lbinferinfos, int *ubinferinfos, int *ects, int *flexenergies, int *perm, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip.c:4936
void SCIPsortDownIntIntInt(int *intarray1, int *intarray2, int *intarray3, int len)
#define SCIPstatisticPrintf
Definition: pub_message.h:107
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip.c:755
static TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
SCIP_RETCODE SCIPprofileCreate(SCIP_PROFILE **profile, int capacity)
Definition: misc.c:4695
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:29454
#define DEFAULT_PRESOLPAIRWISE
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
#define DEFAULT_DETECTDISJUNCTIVE
static SCIP_DECL_CONSFREE(consFreeCumulative)
SCIP_Bool SCIPbtnodeIsRightchild(SCIP_BTNODE *node)
Definition: misc.c:6358
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:49
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:97
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:7587
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:15130
static SCIP_RETCODE consCapacityConstraintsFinder(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
SCIP_BTNODE * SCIPbtGetRoot(SCIP_BT *tree)
Definition: misc.c:6543
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)
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 SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:11453
static SCIP_RETCODE consCheckRedundancy(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *redundant)
static SCIP_RETCODE presolveCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, int *nfixedvars, int *nchgbds, int *ndelconss, int *naddconss, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
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_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip.c:15360
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38311
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:21099
constraint handler for linking binary variables to an integer variable
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:18371
SCIP_BTNODE * SCIPbtnodeGetRightchild(SCIP_BTNODE *node)
Definition: misc.c:6290
#define SCIP_UNKNOWN
Definition: def.h:143
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:16436
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip.c:983
static SCIP_RETCODE propagateUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, int *newlbs, int *newubs, int *lbinferinfos, int *ubinferinfos, int *lsts, int *flexenergies, int *perm, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static void traceThetaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
SCIP_RETCODE SCIPgetBinvarsLinking(SCIP *scip, SCIP_CONS *cons, SCIP_VAR ***binvars, int *nbinvars)
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip.c:5223
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip.c:22476
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip.c:22797
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:16062
#define SCIP_Bool
Definition: def.h:49
static SCIP_RETCODE presolveConsLct(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPincludeDefaultPlugins(SCIP *scip)
static SCIP_RETCODE consdataDropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos)
static SCIP_DECL_CONSPROP(consPropCumulative)
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip.c:3824
#define DEFAULT_DUALPRESOLVE
struct SCIP_NodeData SCIP_NODEDATA
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip.c:1174
int * SCIPgetDurationsCumulative(SCIP *scip, SCIP_CONS *cons)
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
void SCIPprintSysError(const char *message)
Definition: misc.c:7515
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:16626
SCIP_VAR ** SCIPgetVarsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:790
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:7796
#define DEFAULT_USECOVERCUTS
static void freeNodedata(SCIP *scip, SCIP_NODEDATA **nodedata)
SCIP_Bool SCIPprofileFindLeft(SCIP_PROFILE *profile, int timepoint, int *pos)
Definition: misc.c:4821
static SCIP_DECL_EVENTEXEC(eventExecCumulative)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip.h:19222
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:25487
#define SCIP_DECL_CONSEXITPRE(x)
Definition: type_cons.h:137
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:7650
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
Definition: scip.c:22093
static SCIP_RETCODE normalizeDemands(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:16594
static SCIP_RETCODE computeCoreEngeryAfter(SCIP *scip, SCIP_PROFILE *profile, int nvars, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct)
void SCIPbtFree(SCIP_BT **tree)
Definition: misc.c:6451
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:7806
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:7676
SCIP_Bool SCIPbtnodeIsLeftchild(SCIP_BTNODE *node)
Definition: misc.c:6340
SCIP_RETCODE SCIPcreateConsBasicSetpart(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
Definition: cons_setppc.c:8934
SCIP_Longint SCIPgetMemUsed(SCIP *scip)
Definition: scip.c:37975
SCIP_RETCODE SCIPaddVarVlb(SCIP *scip, SCIP_VAR *var, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconstant, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip.c:19547
SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
Definition: scip.c:22125
#define SCIPfreeMemoryArray(scip, ptr)
Definition: scip.h:19178
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:5355
int SCIPgetNRuns(SCIP *scip)
Definition: scip.c:34038
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:16562
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:102
static SCIP_RETCODE branch(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_Bool allowaddcons, SCIP_RESULT *result)
void SCIPprofilePrint(SCIP_PROFILE *profile, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: misc.c:4733
#define SCIPallocMemoryArray(scip, ptr, num)
Definition: scip.h:19161
static SCIP_RETCODE inferboundsEdgeFinding(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS *cons, SCIP_BT *tree, SCIP_BTNODE **leaves, int capacity, int ncands, SCIP_Bool propest, int shift, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
static SCIP_RETCODE consdataDeletePos(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_CONS *cons, int pos)
SCIP_RETCODE SCIPcreateConsBasicCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity)
#define CONSHDLR_NEEDSCONS
int * SCIPprofileGetTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:4775
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:19204
static SCIP_RETCODE computeImpliedEst(SCIP *scip, SCIP_VAR *var, SCIP_HASHMAP *addedvars, int *est)
static SCIP_RETCODE tightenCoefs(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs)
static SCIP_DECL_SORTINDCOMP(consdataCompVar)
Proprule
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:34833
#define DEFAULT_FILLBRANCHCANDS
static SCIP_Bool checkDemands(SCIP *scip, SCIP_CONS *cons)
int * SCIPprofileGetLoads(SCIP_PROFILE *profile)
Definition: misc.c:4785
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38330
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:1317
SCIP_Bool SCIPbtIsEmpty(SCIP_BT *tree)
Definition: misc.c:6533
#define DEFAULT_DETECTVARBOUNDS
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:18583
static SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
SCIP_BTNODE * SCIPbtnodeGetLeftchild(SCIP_BTNODE *node)
Definition: misc.c:6280
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:33424
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:5309
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:10850
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip.c:13596
static SCIP_RETCODE tightenLbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int ect, int lct, int begin, int end, int energy, int *bestlb, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static void createSortedEventpoints(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices, SCIP_Bool local)
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:15953
SCIP_RETCODE SCIPpropCumulativeCondition(SCIP *scip, 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_RETCODE SCIPincludeConshdlrCumulative(SCIP *scip)
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:16584
void SCIPbtSetRoot(SCIP_BT *tree, SCIP_BTNODE *root)
Definition: misc.c:6556
#define SCIPfreeMemory(scip, ptr)
Definition: scip.h:19176
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:16370
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:1984
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip.c:682
static SCIP_RETCODE insertThetanode(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node, SCIP_NODEDATA **nodedatas, int *nnodedatas)
#define CONSHDLR_SEPAFREQ
int SCIPgetHmaxCumulative(SCIP *scip, SCIP_CONS *cons)
void SCIPbtnodeSetParent(SCIP_BTNODE *node, SCIP_BTNODE *parent)
Definition: misc.c:6393
static SCIP_RETCODE removeRedundantConss(SCIP *scip, SCIP_CONS **conss, int nconss, int *ndelconss)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip.c:5516
static SCIP_RETCODE getActiveVar(SCIP *scip, SCIP_VAR **var, int *scalar, int *constant)
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:3636
SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
Definition: scip.c:30637
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:25510
static SCIP_RETCODE computeAlternativeBounds(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks)
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip.c:22772
static void traceLambdaEnergy(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
static SCIP_DECL_CONSPRINT(consPrintCumulative)
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1239
static SCIP_RETCODE consdataCollectLinkingCons(SCIP *scip, SCIP_CONSDATA *consdata)
static SCIP_RETCODE initializeDurations(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnvelop(SCIP_BTNODE *node)
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
int SCIPgetHminCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE constructIncompatibilityGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
static SCIP_RETCODE moveNodeToLambda(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
int SCIPgetNCheckConss(SCIP *scip)
Definition: scip.c:11251
#define DEFAULT_CUTSASCONSS
static int computeCoreWithInterval(int begin, int end, int ect, int lst)
static void collectThetaSubtree(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip.h:19217
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:5199
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:278
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:17642
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:16072
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)
static SCIP_RETCODE normalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
#define SCIPstatistic(x)
Definition: pub_message.h:101
static SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
#define SCIP_Real
Definition: def.h:123
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:7736
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip.c:22747
static SCIP_RETCODE applyAlternativeBoundsBranching(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, SCIP_Bool *branched)
SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:22343
static SCIP_DECL_CONSPARSE(consParseCumulative)
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:18477
static SCIP_DECL_CONSTRANS(consTransCumulative)
#define MIN(x, y)
Definition: memory.c:59
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)
static SCIP_RETCODE fixIntegerVariableUb(SCIP *scip, SCIP_VAR *var, SCIP_Bool uplock, int *nfixedvars)
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:25276
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:26010
#define DEFAULT_EFCHECK
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:19198
#define SCIP_INVALID
Definition: def.h:142
#define EVENTHDLR_DESC
#define DEFAULT_TTEFINFER
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:25414
void SCIPsortInt(int *intarray, int len)
static SCIP_RETCODE createPrecedenceCons(SCIP *scip, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, int distance)
static INFERINFO getInferInfo(PROPRULE proprule, int data1, int data2)
SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
Definition: scip.c:22189
#define SCIP_Longint
Definition: def.h:107
static SCIP_RETCODE detectRedundantConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, int *naddconss)
SCIP_RETCODE SCIPsetEmphasis(SCIP *scip, SCIP_PARAMEMPHASIS paramemphasis, SCIP_Bool quiet)
Definition: scip.c:4104
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:1499
SCIP_CONS * SCIPgetConsLinking(SCIP *scip, SCIP_VAR *intvar)
static SCIP_RETCODE varMayRoundUp(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:17590
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition: scip.c:3779
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:48
static SCIP_RETCODE separateConsOnIntegerVariables(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool lower, SCIP_Bool *separated)
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16052
static void consdataCalcSignature(SCIP_CONSDATA *consdata)
#define DEFAULT_EFINFER
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip.c:3638
static SCIP_RETCODE createCapacityRestriction(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool cutsasconss)
void SCIPgmlWriteOpening(FILE *file, SCIP_Bool directed)
Definition: misc.c:288
static SCIP_Bool impliesVlbPrecedenceCondition(SCIP *scip, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconst, int duration)
#define DEFAULT_DISJUNCTIVE
SCIP_RETCODE SCIPsetHmaxCumulative(SCIP *scip, SCIP_CONS *cons, int hmax)
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
Definition: scip.c:22156
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:38001
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:1901
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:98
#define DEFAULT_USEBDWIDENING
static SCIP_RETCODE tightenCapacity(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
void SCIPswapInts(int *value1, int *value2)
Definition: misc.c:7341
SCIP_RETCODE SCIPbtCreate(SCIP_BT **tree, BMS_BLKMEM *blkmem)
Definition: misc.c:6432
static SCIP_RETCODE collectDemands(SCIP *scip, SCIP_CONSDATA *consdata, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Longint **demands, int *ndemands)
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:22365
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:38409
static SCIP_RETCODE computeEffectiveHorizonCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
int TCLIQUE_WEIGHT
Definition: tclique.h:37
static SCIP_DECL_CONSINITPRE(consInitpreCumulative)
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip.c:32531
static SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
static SCIP_RETCODE computeImpliedLct(SCIP *scip, SCIP_VAR *var, int duration, SCIP_HASHMAP *addedvars, int *lct)
int SCIPprofileGetNTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:4765
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:5585
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:25540
#define SCIPABORT()
Definition: def.h:230
static SCIP_DECL_CONSDELETE(consDeleteCumulative)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:7726
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:6595
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)
default SCIP plugins
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnergy(SCIP_BTNODE *node)
static SCIP_DECL_CONSSEPALP(consSepalpCumulative)
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:7756
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *violated, SCIP_Bool printreason)
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:3903
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3159
SCIP_Bool SCIPbtnodeIsLeaf(SCIP_BTNODE *node)
Definition: misc.c:6330
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip.c:33573
SCIP_RETCODE SCIPcreateConsLinking(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *intvar, SCIP_VAR **binvars, int *vals, int nbinvars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static int inferInfoToInt(INFERINFO inferinfo)
static TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
static SCIP_DECL_CONSRESPROP(consRespropCumulative)
static SCIP_RETCODE varMayRoundDown(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
void SCIPprofileFree(SCIP_PROFILE **profile)
Definition: misc.c:4719
#define CONSHDLR_ENFOPRIORITY
static SCIP_Bool impliesVubPrecedenceCondition(SCIP *scip, SCIP_VAR *var, SCIP_Real vubcoef, SCIP_Real vubconst, int duration)
SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
Definition: scip.c:37988
#define DEFAULT_SEPAOLD
SCIP_RETCODE SCIPnormalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)