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-2016 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_cumulative.c
17  * @brief constraint handler for cumulative constraints
18  * @author Timo Berthold
19  * @author Stefan Heinz
20  * @author Jens Schulz
21  *
22  * Given:
23  * - a set of jobs, represented by their integer start time variables \f$S_j\f$, their array of processing times \f$p_j\f$ and of
24  * their demands \f$d_j\f$.
25  * - an integer resource capacity \f$C\f$
26  *
27  * The cumulative constraint ensures that for each point in time \f$t\f$ \f$\sum_{j: S_j \leq t < S_j + p_j} d_j \leq C\f$ holds.
28  *
29  * Separation:
30  * - can be done using binary start time model, see Pritskers, Watters and Wolfe
31  * - or by just separating relatively weak cuts on the integer start time variables
32  *
33  * Propagation:
34  * - time tabling, Klein & Scholl (1999)
35  * - Edge-finding from Petr Vilim, adjusted and simplified for dynamic repropagation
36  * (2009)
37  * - energetic reasoning, see Baptiste, Le Pape, Nuijten (2001)
38  *
39  */
40 
41 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
42 
43 #include <assert.h>
44 #include <string.h>
45 
46 #include "tclique/tclique.h"
47 #include "scip/cons_cumulative.h"
48 #include "scip/cons_linking.h"
49 #include "scip/cons_knapsack.h"
50 #include "scip/scipdefplugins.h"
51 
52 /**@name Constraint handler properties
53  *
54  * @{
55  */
56 
57 /* constraint handler properties */
58 #define CONSHDLR_NAME "cumulative"
59 #define CONSHDLR_DESC "cumulative constraint handler"
60 #define CONSHDLR_SEPAPRIORITY 2100000 /**< priority of the constraint handler for separation */
61 #define CONSHDLR_ENFOPRIORITY -2040000 /**< priority of the constraint handler for constraint enforcing */
62 #define CONSHDLR_CHECKPRIORITY -3030000 /**< priority of the constraint handler for checking feasibility */
63 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
64 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
65 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
66  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
67 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
68 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
69 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
70 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
71 
72 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
73 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
74 
75 /**@} */
76 
77 /**@name Default parameter values
78  *
79  * @{
80  */
81 
82 /* default parameter values */
83 
84 /* separation */
85 #define DEFAULT_USEBINVARS FALSE /**< should the binary representation be used? */
86 #define DEFAULT_LOCALCUTS FALSE /**< should cuts be added only locally? */
87 #define DEFAULT_USECOVERCUTS TRUE /**< should covering cuts be added? */
88 #define DEFAULT_CUTSASCONSS TRUE /**< should the cuts be created as knapsack constraints? */
89 #define DEFAULT_SEPAOLD TRUE /**< shall old sepa algo be applied? */
90 
91 /* propagation */
92 #define DEFAULT_TTINFER TRUE /**< should time-table (core-times) propagator be used to infer bounds? */
93 #define DEFAULT_EFCHECK FALSE /**< should edge-finding be used to detect an overload? */
94 #define DEFAULT_EFINFER FALSE /**< should edge-finding be used to infer bounds? */
95 #define DEFAULT_USEADJUSTEDJOBS FALSE /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
96 #define DEFAULT_TTEFCHECK TRUE /**< should time-table edge-finding be used to detect an overload? */
97 #define DEFAULT_TTEFINFER TRUE /**< should time-table edge-finding be used to infer bounds? */
98 
99 /* presolving */
100 #define DEFAULT_DUALPRESOLVE TRUE /**< should dual presolving be applied? */
101 #define DEFAULT_COEFTIGHTENING FALSE /**< should coeffisient tightening be applied? */
102 #define DEFAULT_NORMALIZE TRUE /**< should demands and capacity be normalized? */
103 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
104 #define DEFAULT_DISJUNCTIVE TRUE /**< extract disjunctive constraints? */
105 #define DEFAULT_DETECTDISJUNCTIVE TRUE /**< search for conflict set via maximal cliques to detect disjunctive constraints */
106 #define DEFAULT_DETECTVARBOUNDS TRUE /**< search for conflict set via maximal cliques to detect variable bound constraints */
107 #define DEFAULT_MAXNODES 10000LL /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
109 /* enforcement */
110 #define DEFAULT_FILLBRANCHCANDS FALSE /**< should branching candidates be added to storage? */
112 /* conflict analysis */
113 #define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used during conflict analysis? */
115 /**@} */
116 
117 /**@name Event handler properties
118  *
119  * @{
120  */
121 
122 #define EVENTHDLR_NAME "cumulative"
123 #define EVENTHDLR_DESC "bound change event handler for cumulative constraints"
125 /**@} */
126 
127 /*
128  * Data structures
129  */
130 
131 /** constraint data for cumulative constraints */
132 struct SCIP_ConsData
133 {
134  SCIP_VAR** vars; /**< array of variable representing the start time of each job */
135  SCIP_Bool* downlocks; /**< array to store if the variable has a down lock */
136  SCIP_Bool* uplocks; /**< array to store if the variable has an uplock */
137  SCIP_CONS** linkingconss; /**< array of linking constraints for the integer variables */
138  SCIP_ROW** demandrows; /**< array of rows of linear relaxation of this problem */
139  SCIP_ROW** scoverrows; /**< array of rows of small cover cuts of this problem */
140  SCIP_ROW** bcoverrows; /**< array of rows of big cover cuts of this problem */
141  int* demands; /**< array containing corresponding demands */
142  int* durations; /**< array containing corresponding durations */
143  SCIP_Real resstrength1; /**< stores the resource strength 1*/
144  SCIP_Real resstrength2; /**< stores the resource strength 2 */
145  SCIP_Real cumfactor1; /**< stroes the cumulativeness of the constraint */
146  SCIP_Real disjfactor1; /**< stores the disjunctiveness of the constraint */
147  SCIP_Real disjfactor2; /**< stores the disjunctiveness of the constraint */
148  SCIP_Real estimatedstrength;
149  int nvars; /**< number of variables */
150  int varssize; /**< size of the arrays */
151  int ndemandrows; /**< number of rows of cumulative constrint for linear relaxation */
152  int demandrowssize; /**< size of array rows of demand rows */
153  int nscoverrows; /**< number of rows of small cover cuts */
154  int scoverrowssize; /**< size of array of small cover cuts */
155  int nbcoverrows; /**< number of rows of big cover cuts */
156  int bcoverrowssize; /**< size of array of big cover cuts */
157  int capacity; /**< available cumulative capacity */
158 
159  int hmin; /**< left bound of time axis to be considered (including hmin) */
160  int hmax; /**< right bound of time axis to be considered (not including hmax) */
161 
162  unsigned int signature; /**< constraint signature which is need for pairwise comparison */
163 
164  unsigned int validsignature:1; /**< is the signature valid */
165  unsigned int normalized:1; /**< is the constraint normalized */
166  unsigned int covercuts:1; /**< cover cuts are created? */
167  unsigned int propagated:1; /**< is constraint propagted */
168  unsigned int varbounds:1; /**< bool to store if variable bound strengthening was already preformed */
169  unsigned int triedsolving:1; /**< bool to store if we tried already to solve that constraint as independent subproblem */
170 
171 #ifdef SCIP_STATISTIC
172  int maxpeak;
173 #endif
174 };
175 
176 /** constraint handler data */
177 struct SCIP_ConshdlrData
178 {
179  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
180 
181  SCIP_Bool usebinvars; /**< should the binary variables be used? */
182  SCIP_Bool cutsasconss; /**< should the cumulative constraint create cuts as knapsack constraints? */
183  SCIP_Bool ttinfer; /**< should time-table (core-times) propagator be used to infer bounds? */
184  SCIP_Bool efcheck; /**< should edge-finding be used to detect an overload? */
185  SCIP_Bool efinfer; /**< should edge-finding be used to infer bounds? */
186  SCIP_Bool useadjustedjobs; /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
187  SCIP_Bool ttefcheck; /**< should time-table edge-finding be used to detect an overload? */
188  SCIP_Bool ttefinfer; /**< should time-table edge-finding be used to infer bounds? */
189  SCIP_Bool localcuts; /**< should cuts be added only locally? */
190  SCIP_Bool usecovercuts; /**< should covering cuts be added? */
191  SCIP_Bool sepaold; /**< shall old sepa algo be applied? */
192 
193 
194  SCIP_Bool fillbranchcands; /**< should branching candidates be added to storage? */
195 
196  SCIP_Bool dualpresolve; /**< should dual presolving be applied? */
197  SCIP_Bool coeftightening; /**< should coeffisient tightening be applied? */
198  SCIP_Bool normalize; /**< should demands and capacity be normalized? */
199  SCIP_Bool disjunctive; /**< extract disjunctive constraints? */
200  SCIP_Bool detectdisjunctive; /**< search for conflict set via maximal cliques to detect disjunctive constraints */
201  SCIP_Bool detectvarbounds; /**< search for conflict set via maximal cliques to detect variable bound constraints */
202  SCIP_Bool usebdwidening; /**< should bound widening be used during conflict analysis? */
203  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
204  SCIP_Bool detectedredundant; /**< was detection of redundant constraints already performed? */
205 
206  SCIP_Longint maxnodes; /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
207 
208  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)); /**< method to use a single cumulative condition */
209 
210  /* statistic values which are collected if SCIP_STATISTIC is defined */
211 #ifdef SCIP_STATISTIC
212  SCIP_Longint nlbtimetable; /**< number of times the lower bound was tightened by the time-table propagator */
213  SCIP_Longint nubtimetable; /**< number of times the upper bound was tightened by the time-table propagator */
214  SCIP_Longint ncutofftimetable; /**< number of times the a cutoff was detected due to time-table propagator */
215  SCIP_Longint nlbedgefinder; /**< number of times the lower bound was tightened by the edge-finder propagator */
216  SCIP_Longint nubedgefinder; /**< number of times the upper bound was tightened by the edge-finder propagator */
217  SCIP_Longint ncutoffedgefinder; /**< number of times the a cutoff was detected due to edge-finder propagator */
218  SCIP_Longint ncutoffoverload; /**< number of times the a cutoff was detected due to overload checking via edge-finding */
219  SCIP_Longint nlbTTEF; /**< number of times the lower bound was tightened by time-table edge-finding */
220  SCIP_Longint nubTTEF; /**< number of times the upper bound was tightened by time-table edge-finding */
221  SCIP_Longint ncutoffoverloadTTEF;/**< number of times the a cutoff was detected due to overload checking via time-table edge-finding */
222 
223  int nirrelevantjobs; /**< number of time a irrelevant/redundant jobs was removed form a constraint */
224  int nalwaysruns; /**< number of time a job removed form a constraint which run completely during the effective horizon */
225  int nremovedlocks; /**< number of times a up or down lock was removed */
226  int ndualfixs; /**< number of times a dual fix was performed by a single constraint */
227  int ndecomps; /**< number of times a constraint was decomposed */
228  int ndualbranchs; /**< number of times a dual branch was discoverd and applicable via probing */
229  int nallconsdualfixs; /**< number of times a dual fix was performed due to knowledge of all cumulative constraints */
230  int naddedvarbounds; /**< number of added variable bounds constraints */
231  int naddeddisjunctives; /**< number of added disjunctive constraints */
232 
233  SCIP_Bool iscopy; /**< Boolean to store if constraint handler is part of a copy */
234 #endif
235 };
236 
237 /**@name Inference Information Methods
238  *
239  * An inference information can be passed with each domain reduction to SCIP. This information is passed back to the
240  * constraint handler if the corresponding bound change has to be explained. It can be used to store information which
241  * help to construct a reason/explanation for a bound change. The inference information is limited to size of integer.
242  *
243  * In case of the cumulative constraint handler we store the used propagation algorithms for that particular bound
244  * change and the earliest start and latest completion time of all jobs in the conflict set.
245  *
246  * @{
247  */
248 
249 /** Propagation rules */
250 enum Proprule
251 {
252  PROPRULE_1_CORETIMES = 1, /**< core-time propagator */
253  PROPRULE_2_EDGEFINDING = 2, /**< edge-finder */
254  PROPRULE_3_TTEF = 3 /**< time-table edeg-finding */
255 };
256 typedef enum Proprule PROPRULE;
258 /** inference information */
259 struct InferInfo
260 {
261  union
262  {
263  /** struct to use the inference information */
264  struct
265  {
266  unsigned int proprule:2; /**< propagation rule that was applied */
267  unsigned int data1:15; /**< data field one */
268  unsigned int data2:15; /**< data field two */
269  } asbits;
270  int asint; /**< inference information as a single int value */
271  } val;
272 };
273 typedef struct InferInfo INFERINFO;
275 /** converts an integer into an inference information */
276 static
277 INFERINFO intToInferInfo(
278  int i /**< integer to convert */
279  )
280 {
281  INFERINFO inferinfo;
282 
283  inferinfo.val.asint = i;
284 
285  return inferinfo;
286 }
287 
288 /** converts an inference information into an int */
289 static
290 int inferInfoToInt(
291  INFERINFO inferinfo /**< inference information to convert */
292  )
293 {
294  return inferinfo.val.asint;
295 }
296 
297 /** returns the propagation rule stored in the inference information */
298 static
300  INFERINFO inferinfo /**< inference information to convert */
301  )
302 {
303  return (PROPRULE) inferinfo.val.asbits.proprule;
304 }
305 
306 /** returns data field one of the inference information */
307 static
309  INFERINFO inferinfo /**< inference information to convert */
310  )
311 {
312  return (int) inferinfo.val.asbits.data1;
313 }
314 
315 /** returns data field two of the inference information */
316 static
318  INFERINFO inferinfo /**< inference information to convert */
319  )
320 {
321  return (int) inferinfo.val.asbits.data2;
322 }
323 
324 
325 /** constructs an inference information out of a propagation rule, an earliest start and a latest completion time */
326 static
327 INFERINFO getInferInfo(
328  PROPRULE proprule, /**< propagation rule that deduced the value */
329  int data1, /**< data field one */
330  int data2 /**< data field two */
331  )
332 {
333  INFERINFO inferinfo;
334 
335  /* check that the data menber are in the range of the available bits */
336  assert((int)proprule <= (1<<2)-1); /*lint !e685*/
337  assert(data1 >= 0 && data1 < (1<<15));
338  assert(data2 >= 0 && data2 < (1<<15));
339 
340  inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
341  inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
342  inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
343 
344  return inferinfo;
345 }
346 
347 /**@} */
348 
349 /*
350  * Local methods
351  */
352 
353 /**@name Miscellaneous Methods
354  *
355  * @{
356  */
357 
358 #ifndef NDEBUG
359 
360 /** compute the core of a job which lies in certain interval [begin, end) */
361 static
363  int begin, /**< begin of the interval */
364  int end, /**< end of the interval */
365  int ect, /**< earliest completion time */
366  int lst /**< latest start time */
367  )
368 {
369  int core;
370 
371  core = MAX(0, MIN(end, ect) - MAX(lst, begin));
372 
373  return core;
374 }
375 #else
376 #define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
377 #endif
378 
379 /** returns the implied earliest start time */
380 static
382  SCIP* scip, /**< SCIP data structure */
383  SCIP_VAR* var, /**< variable for which the implied est should be returned */
384  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
385  int* est /**< pointer to store the implied earliest start time */
386  )
387 { /*lint --e{715}*/
388 #if 0
389  SCIP_VAR** vbdvars;
390  SCIP_VAR* vbdvar;
391  SCIP_Real* vbdcoefs;
392  SCIP_Real* vbdconsts;
393  void* image;
394  int nvbdvars;
395  int v;
396 #endif
397 
398  (*est) = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
399 
400 #if 0
401  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
402 
403  nvbdvars = SCIPvarGetNVlbs(var);
404  vbdvars = SCIPvarGetVlbVars(var);
405  vbdcoefs = SCIPvarGetVlbCoefs(var);
406  vbdconsts = SCIPvarGetVlbConstants(var);
407 
408  for( v = 0; v < nvbdvars; ++v )
409  {
410  vbdvar = vbdvars[v];
411  assert(vbdvar != NULL);
412 
413  image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
414 
415  if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
416  {
417  int duration;
418  int vbdconst;
419 
420  duration = (int)(size_t)image;
421  vbdconst = SCIPconvertRealToInt(scip, vbdconsts[v]);
422 
423  SCIPdebugMessage("check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
425  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
426 
427  if( duration >= vbdconst )
428  {
429  int impliedest;
430 
431  impliedest = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
432 
433  if( (*est) < impliedest )
434  {
435  (*est) = impliedest;
436 
437  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
438  }
439  }
440  }
441  }
442 #endif
443 
444  return SCIP_OKAY;
445 }
446 
447 /** returns the implied latest completion time */
448 static
450  SCIP* scip, /**< SCIP data structure */
451  SCIP_VAR* var, /**< variable for which the implied est should be returned */
452  int duration, /**< duration of the given job */
453  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
454  int* lct /**< pointer to store the implied latest completion time */
455  )
456 { /*lint --e{715}*/
457 #if 0
458  SCIP_VAR** vbdvars;
459  SCIP_VAR* vbdvar;
460  SCIP_Real* vbdcoefs;
461  SCIP_Real* vbdconsts;
462  int nvbdvars;
463  int v;
464 #endif
465 
466  (*lct) = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
467 
468 #if 0
469  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
470 
471  nvbdvars = SCIPvarGetNVubs(var);
472  vbdvars = SCIPvarGetVubVars(var);
473  vbdcoefs = SCIPvarGetVubCoefs(var);
474  vbdconsts = SCIPvarGetVubConstants(var);
475 
476  for( v = 0; v < nvbdvars; ++v )
477  {
478  vbdvar = vbdvars[v];
479  assert(vbdvar != NULL);
480 
481  if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
482  {
483  int vbdconst;
484 
485  vbdconst = SCIPconvertRealToInt(scip, -vbdconsts[v]);
486 
487  SCIPdebugMessage("check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
489  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
490 
491  if( duration >= -vbdconst )
492  {
493  int impliedlct;
494 
495  impliedlct = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
496 
497  if( (*lct) > impliedlct )
498  {
499  (*lct) = impliedlct;
500 
501  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
502  }
503  }
504  }
505  }
506 #endif
507 
508  return SCIP_OKAY;
509 }
510 
511 /** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
512 static
514  SCIP* scip, /**< SCIP data structure */
515  SCIP_CONSDATA* consdata, /**< constraint data */
516  SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
517  int** coefs, /**< pointer to store the coefficients */
518  int* nvars, /**< number if collect binary variables */
519  int* startindices, /**< permutation with rspect to the start times */
520  int curtime, /**< current point in time */
521  int nstarted, /**< number of jobs that start before the curtime or at curtime */
522  int nfinished /**< number of jobs that finished before curtime or at curtime */
523  )
524 {
525  int nrowvars;
526  int startindex;
527  int size;
528 
529  size = 10;
530  nrowvars = 0;
531  startindex = nstarted - 1;
532 
533  SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
534  SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
535 
536  /* search for the (nstarted - nfinished) jobs which are active at curtime */
537  while( nstarted - nfinished > nrowvars )
538  {
539  SCIP_VAR* var;
540  int endtime;
541  int duration;
542  int demand;
543  int varidx;
544 
545  /* collect job information */
546  varidx = startindices[startindex];
547  assert(varidx >= 0 && varidx < consdata->nvars);
548 
549  var = consdata->vars[varidx];
550  duration = consdata->durations[varidx];
551  demand = consdata->demands[varidx];
552  assert(var != NULL);
553 
554  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
555 
556  /* check the end time of this job is larger than the curtime; in this case the job is still running */
557  if( endtime > curtime )
558  {
559  SCIP_VAR** binvars;
560  int* vals;
561  int nbinvars;
562  int start;
563  int end;
564  int b;
565 
566  /* check if the linking constraints exists */
567  assert(SCIPexistsConsLinking(scip, var));
568  assert(SCIPgetConsLinking(scip, var) != NULL);
569  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
570 
571  /* collect linking constraint information */
572  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
573  vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
574 
575  start = curtime - duration + 1;
576  end = MIN(curtime, endtime - duration);
577 
578  for( b = 0; b < nbinvars; ++b )
579  {
580  if( vals[b] < start )
581  continue;
582 
583  if( vals[b] > end )
584  break;
585 
586  assert(binvars[b] != NULL);
587 
588  /* ensure array proper array size */
589  if( size == *nvars )
590  {
591  size *= 2;
592  SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
593  SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
594  }
595 
596  (*vars)[*nvars] = binvars[b];
597  (*coefs)[*nvars] = demand;
598  (*nvars)++;
599  }
600  nrowvars++;
601  }
602 
603  startindex--;
604  }
605 
606  return SCIP_OKAY;
607 }
608 
609 /** collect all integer variable which belong to jobs which can run at the point of interest */
610 static
612  SCIP* scip, /**< SCIP data structure */
613  SCIP_CONSDATA* consdata, /**< constraint data */
614  SCIP_VAR*** activevars, /**< jobs that are currently running */
615  int* startindices, /**< permutation with rspect to the start times */
616  int curtime, /**< current point in time */
617  int nstarted, /**< number of jobs that start before the curtime or at curtime */
618  int nfinished, /**< number of jobs that finished before curtime or at curtime */
619  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
620  int* lhs /**< lhs for the new row sum of lbs + minoffset */
621  )
622 {
623  SCIP_VAR* var;
624  int startindex;
625  int endtime;
626  int duration;
627  int starttime;
628 
629  int varidx;
630  int sumofstarts;
631  int mindelta;
632  int counter;
633 
634  assert(curtime >= consdata->hmin);
635  assert(curtime < consdata->hmax);
636 
637  counter = 0;
638  sumofstarts = 0;
639 
640  mindelta = INT_MAX;
641 
642  startindex = nstarted - 1;
643 
644  /* search for the (nstarted - nfinished) jobs which are active at curtime */
645  while( nstarted - nfinished > counter )
646  {
647  assert(startindex >= 0);
648 
649  /* collect job information */
650  varidx = startindices[startindex];
651  assert(varidx >= 0 && varidx < consdata->nvars);
652 
653  var = consdata->vars[varidx];
654  duration = consdata->durations[varidx];
655  assert(duration > 0);
656  assert(var != NULL);
657 
658  if( lower )
659  starttime = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
660  else
661  starttime = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
662 
663  endtime = MIN(starttime + duration, consdata->hmax);
664 
665  /* check the end time of this job is larger than the curtime; in this case the job is still running */
666  if( endtime > curtime )
667  {
668  (*activevars)[counter] = var;
669  sumofstarts += starttime;
670  mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
671  counter++;
672  }
673 
674  startindex--;
675  }
676 
677  assert(mindelta > 0);
678  *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
679 
680  return SCIP_OKAY;
681 }
682 
683 /** initialize the sorted event point arrays */
684 static
686  SCIP* scip, /**< SCIP data structure */
687  int nvars, /**< number of start time variables (activities) */
688  SCIP_VAR** vars, /**< array of start time variables */
689  int* durations, /**< array of durations per start time variable */
690  int* starttimes, /**< array to store sorted start events */
691  int* endtimes, /**< array to store sorted end events */
692  int* startindices, /**< permutation with rspect to the start times */
693  int* endindices, /**< permutation with rspect to the end times */
694  SCIP_Bool local /**< shall local bounds be used */
695  )
696 {
697  SCIP_VAR* var;
698  int j;
699 
700  assert(vars != NULL || nvars == 0);
701 
702  /* assign variables, start and endpoints to arrays */
703  for ( j = 0; j < nvars; ++j )
704  {
705  assert(vars != NULL);
706 
707  var = vars[j];
708  assert(var != NULL);
709 
710  if( local )
711  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
712  else
713  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
714 
715  startindices[j] = j;
716 
717  if( local )
718  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
719  else
720  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
721 
722  endindices[j] = j;
723 
724  }
725 
726  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
727  SCIPsortIntInt(starttimes, startindices, j);
728  SCIPsortIntInt(endtimes, endindices, j);
729 }
730 
731 /** initialize the sorted event point arrays w.r.t. the given primal solutions */
732 static
734  SCIP* scip, /**< SCIP data structure */
735  SCIP_SOL* sol, /**< solution */
736  int nvars, /**< number of start time variables (activities) */
737  SCIP_VAR** vars, /**< array of start time variables */
738  int* durations, /**< array of durations per start time variable */
739  int* starttimes, /**< array to store sorted start events */
740  int* endtimes, /**< array to store sorted end events */
741  int* startindices, /**< permutation with rspect to the start times */
742  int* endindices /**< permutation with rspect to the end times */
743  )
744 {
745  SCIP_VAR* var;
746  int j;
747 
748  assert(vars != NULL || nvars == 0);
749 
750  /* assign variables, start and endpoints to arrays */
751  for ( j = 0; j < nvars; ++j )
752  {
753  assert(vars != NULL);
754 
755  var = vars[j];
756  assert(var != NULL);
757 
758  starttimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
759  startindices[j] = j;
760 
761  endtimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
762  endindices[j] = j;
763 
764  }
765 
766  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
767  SCIPsortIntInt(starttimes, startindices, j);
768  SCIPsortIntInt(endtimes, endindices, j);
769 }
770 
771 /** initialize the sorted event point arrays
772  *
773  * @todo Check the separation process!
774  */
775 static
777  SCIP* scip, /**< SCIP data structure */
778  SCIP_CONSDATA* consdata, /**< constraint data */
779  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
780  int* starttimes, /**< array to store sorted start events */
781  int* endtimes, /**< array to store sorted end events */
782  int* startindices, /**< permutation with rspect to the start times */
783  int* endindices, /**< permutation with rspect to the end times */
784  int* nvars, /**< number of variables that are integral */
785  SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
786  )
787 {
788  SCIP_VAR* var;
789  int tmpnvars;
790  int j;
791 
792  tmpnvars = consdata->nvars;
793  *nvars = 0;
794 
795  /* assign variables, start and endpoints to arrays */
796  for ( j = 0; j < tmpnvars; ++j )
797  {
798  var = consdata->vars[j];
799  assert(var != NULL);
800  assert(consdata->durations[j] > 0);
801  assert(consdata->demands[j] > 0);
802 
803  if( lower )
804  {
805  /* only consider jobs that are at their lower or upper bound */
806  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
807  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
808  continue;
809 
810 
811  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
812  startindices[*nvars] = j;
813 
814  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
815  endindices[*nvars] = j;
816 
817  SCIPdebugMessage("%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
818  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
819  consdata->durations[j],
820  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
821  consdata->demands[startindices[*nvars]]);
822 
823  (*nvars)++;
824  }
825  else
826  {
827  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
828  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
829  continue;
830 
831  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
832  startindices[*nvars] = j;
833 
834  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
835  endindices[*nvars] = j;
836 
837  SCIPdebugMessage("%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
838  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
839  consdata->durations[j],
840  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
841  consdata->demands[startindices[*nvars]]);
842 
843  (*nvars)++;
844  }
845  }
846 
847  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
848  SCIPsortIntInt(starttimes, startindices, *nvars);
849  SCIPsortIntInt(endtimes, endindices, *nvars);
850 
851 #ifdef SCIP_DEBUG
852  SCIPdebugMessage("sorted output %d\n", *nvars);
853 
854  for ( j = 0; j < *nvars; ++j )
855  {
856  SCIPdebugMessage("%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
857  startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
858  consdata->demands[startindices[j]]);
859  }
860 
861  for ( j = 0; j < *nvars; ++j )
862  {
863  SCIPdebugMessage("%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
864  consdata->demands[endindices[j]]);
865  }
866 #endif
867 }
868 
869 #ifdef SCIP_STATISTIC
870 /** this method checks for relevant intervals for energetic reasoning */
871 static
872 SCIP_RETCODE computeRelevantEnergyIntervals(
873  SCIP* scip, /**< SCIP data structure */
874  int nvars, /**< number of start time variables (activities) */
875  SCIP_VAR** vars, /**< array of start time variables */
876  int* durations, /**< array of durations */
877  int* demands, /**< array of demands */
878  int capacity, /**< cumulative capacity */
879  int hmin, /**< left bound of time axis to be considered (including hmin) */
880  int hmax, /**< right bound of time axis to be considered (not including hmax) */
881  int** timepoints, /**< array to store relevant points in time */
882  SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
883  int* ntimepoints, /**< pointer to store the number of timepoints */
884  int* maxdemand, /**< pointer to store maximum over all demands */
885  SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
886  )
887 {
888  int* starttimes; /* stores when each job is starting */
889  int* endtimes; /* stores when each job ends */
890  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
891  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
892 
893  SCIP_Real totaldemand;
894  int curtime; /* point in time which we are just checking */
895  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
896 
897  int j;
898 
899  assert( scip != NULL );
900  assert(durations != NULL);
901  assert(demands != NULL);
902  assert(capacity >= 0);
903 
904  /* if no activities are associated with this cumulative then this constraint is redundant */
905  if( nvars == 0 )
906  return SCIP_OKAY;
907 
908  assert(vars != NULL);
909 
910  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
911  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
912  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
913  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
914 
915  /* create event point arrays */
916  createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
917 
918  endindex = 0;
919  totaldemand = 0.0;
920 
921  *ntimepoints = 0;
922  (*timepoints)[0] = starttimes[0];
923  (*cumulativedemands)[0] = 0;
924  *maxdemand = 0;
925 
926  /* check each startpoint of a job whether the capacity is kept or not */
927  for( j = 0; j < nvars; ++j )
928  {
929  int lct;
930  int idx;
931 
932  curtime = starttimes[j];
933 
934  if( curtime >= hmax )
935  break;
936 
937  /* free all capacity usages of jobs the are no longer running */
938  while( endindex < nvars && endtimes[endindex] <= curtime )
939  {
940  int est;
941 
942  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
943  {
944  (*ntimepoints)++;
945  (*timepoints)[*ntimepoints] = endtimes[endindex];
946  (*cumulativedemands)[*ntimepoints] = 0;
947  }
948 
949  idx = endindices[endindex];
950  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
951  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
952  endindex++;
953 
954  (*cumulativedemands)[*ntimepoints] = totaldemand;
955  }
956 
957  idx = startindices[j];
958  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
959  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
960 
961  if( (*timepoints)[*ntimepoints] < curtime )
962  {
963  (*ntimepoints)++;
964  (*timepoints)[*ntimepoints] = curtime;
965  (*cumulativedemands)[*ntimepoints] = 0;
966  }
967 
968  (*cumulativedemands)[*ntimepoints] = totaldemand;
969 
970  /* add the relative capacity requirements for all job which start at the curtime */
971  while( j+1 < nvars && starttimes[j+1] == curtime )
972  {
973  ++j;
974  idx = startindices[j];
975  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
976  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
977 
978  (*cumulativedemands)[*ntimepoints] = totaldemand;
979  }
980  } /*lint --e{850}*/
981 
982  /* free all capacity usages of jobs that are no longer running */
983  while( endindex < nvars/* && endtimes[endindex] < hmax*/)
984  {
985  int est;
986  int idx;
987 
988  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
989  {
990  (*ntimepoints)++;
991  (*timepoints)[*ntimepoints] = endtimes[endindex];
992  (*cumulativedemands)[*ntimepoints] = 0;
993  }
994 
995  idx = endindices[endindex];
996  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
997  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
998  (*cumulativedemands)[*ntimepoints] = totaldemand;
999 
1000  ++endindex;
1001  }
1002 
1003  (*ntimepoints)++;
1004  /* compute minimum free capacity */
1005  (*minfreecapacity) = INT_MAX;
1006  for( j = 0; j < *ntimepoints; ++j )
1007  {
1008  if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
1009  *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
1010  }
1011 
1012  /* free buffer arrays */
1013  SCIPfreeBufferArray(scip, &endindices);
1014  SCIPfreeBufferArray(scip, &startindices);
1015  SCIPfreeBufferArray(scip, &endtimes);
1016  SCIPfreeBufferArray(scip, &starttimes);
1017 
1018  return SCIP_OKAY;
1019 }
1020 
1021 /** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1022 static
1023 SCIP_RETCODE evaluateCumulativeness(
1024  SCIP* scip, /**< pointer to scip */
1025  SCIP_CONS* cons /**< cumulative constraint */
1026  )
1027 {
1028  SCIP_CONSDATA* consdata;
1029  int nvars;
1030  int v;
1031  int capacity;
1032 
1033  /* output values: */
1034  SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
1035  SCIP_Real cumfactor1;
1036  SCIP_Real resstrength1; /* overall strength */
1037  SCIP_Real resstrength2; /* timepoint wise maximum */
1038 
1039  /* helpful variables: */
1040  SCIP_Real globalpeak;
1041  SCIP_Real globalmaxdemand;
1042 
1043  /* get constraint data structure */
1044  consdata = SCIPconsGetData(cons);
1045  assert(consdata != NULL);
1046 
1047  nvars = consdata->nvars;
1048  capacity = consdata->capacity;
1049  globalpeak = 0.0;
1050  globalmaxdemand = 0.0;
1051 
1052  disjfactor2 = 0.0;
1053  cumfactor1 = 0.0;
1054  resstrength2 = 0.0;
1055 
1056  /* check each starting time (==each job, but inefficient) */
1057  for( v = 0; v < nvars; ++v )
1058  {
1059  SCIP_Real peak;
1060  SCIP_Real maxdemand;
1061  SCIP_Real deltademand;
1062  int ndemands;
1063  int nlarge;
1064 
1065  int timepoint;
1066  int j;
1067  timepoint = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
1068  peak = consdata->demands[v];
1069  ndemands = 1;
1070  maxdemand = 0;
1071  nlarge = 0;
1072 
1073  if( consdata->demands[v] > capacity / 3 )
1074  nlarge++;
1075 
1076  for( j = 0; j < nvars; ++j )
1077  {
1078  int lb;
1079 
1080  if( j == v )
1081  continue;
1082 
1083  maxdemand = 0.0;
1084  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
1085 
1086  if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
1087  {
1088  peak += consdata->demands[j];
1089  ndemands++;
1090 
1091  if( consdata->demands[j] > consdata->capacity / 3 )
1092  nlarge++;
1093  }
1094  }
1095 
1096  deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
1097  globalpeak = MAX(globalpeak, peak);
1098  globalmaxdemand = MAX(globalmaxdemand, maxdemand);
1099 
1100  if( peak > capacity )
1101  {
1102  disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
1103  cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
1104  resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
1105  }
1106  }
1107 
1108  resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
1109 
1110  consdata->maxpeak = SCIPconvertRealToInt(scip, globalpeak);
1111  consdata->disjfactor2 = disjfactor2;
1112  consdata->cumfactor1 = cumfactor1;
1113  consdata->resstrength2 = resstrength2;
1114  consdata->resstrength1 = resstrength1;
1115 
1116  /* get estimated res strength */
1117  {
1118  int* timepoints;
1119  SCIP_Real* estimateddemands;
1120  int ntimepoints;
1121  int maxdemand;
1122  SCIP_Real minfreecapacity;
1123 
1124  SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
1125  SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
1126 
1127  ntimepoints = 0;
1128  minfreecapacity = INT_MAX;
1129 
1130 
1131  SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
1132  consdata->durations, consdata->demands,
1133  capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1134  &ntimepoints, &maxdemand, &minfreecapacity) );
1135 
1136  /* free buffer arrays */
1137  SCIPfreeBufferArray(scip, &estimateddemands);
1138  SCIPfreeBufferArray(scip, &timepoints);
1139 
1140  consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
1141  }
1142 
1143  SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
1144  SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
1145  consdata->estimatedstrength);
1146 
1147  return SCIP_OKAY;
1148 }
1149 #endif
1150 
1151 /** gets the active variables together with the constant */
1152 static
1154  SCIP* scip, /**< SCIP data structure */
1155  SCIP_VAR** var, /**< pointer to store the active variable */
1156  int* scalar, /**< pointer to store the scalar */
1157  int* constant /**< pointer to store the constant */
1158  )
1159 {
1160  if( !SCIPvarIsActive(*var) )
1161  {
1162  SCIP_Real realscalar;
1163  SCIP_Real realconstant;
1164 
1165  realscalar = 1.0;
1166  realconstant = 0.0;
1167 
1169 
1170  /* transform variable to active variable */
1171  SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
1172  assert(!SCIPisZero(scip, realscalar));
1173  assert(SCIPvarIsActive(*var));
1174 
1175  if( realconstant < 0.0 )
1176  (*constant) = -SCIPconvertRealToInt(scip, -realconstant);
1177  else
1178  (*constant) = SCIPconvertRealToInt(scip, realconstant);
1179 
1180  if( realscalar < 0.0 )
1181  (*scalar) = -SCIPconvertRealToInt(scip, -realscalar);
1182  else
1183  (*scalar) = SCIPconvertRealToInt(scip, realscalar);
1184  }
1185  else
1186  {
1187  (*scalar) = 1;
1188  (*constant) = 0;
1189  }
1190 
1191  assert(*scalar != 0);
1192 
1193  return SCIP_OKAY;
1194 }
1195 
1196 /** computes the total energy of all jobs */
1197 static
1198 int computeTotalEnergy(
1199  int* durations, /**< array of job durations */
1200  int* demands, /**< array of job demands */
1201  int njobs /**< number of jobs */
1202  )
1203 {
1204  int energy;
1205  int j;
1206 
1207  energy = 0;
1208 
1209  for( j = 0; j < njobs; ++j )
1210  energy += durations[j] * demands[j];
1211 
1212  return energy;
1213 }
1214 
1215 /**@} */
1216 
1217 /**@name Default method to solve a cumulative condition
1218  *
1219  * @{
1220  */
1221 
1222 /** solve single cumulative condition using SCIP and a single cumulative constraint */
1223 static
1224 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1226  SCIP* subscip;
1227  SCIP_VAR** subvars;
1228  SCIP_CONS* cons;
1229  SCIP_RETCODE retcode;
1230  char name[SCIP_MAXSTRLEN];
1231  int v;
1232 
1233  assert(njobs > 0);
1234 
1235  (*solved) = FALSE;
1236  (*infeasible) = FALSE;
1237  (*unbounded) = FALSE;
1238  (*error) = FALSE;
1239 
1240  SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1241 
1242  /* initialize the sub-problem */
1243  SCIP_CALL( SCIPcreate(&subscip) );
1244 
1245  /* copy all plugins */
1247 
1248  /* create the subproblem */
1249  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1250 
1251  SCIP_CALL( SCIPallocMemoryArray(subscip, &subvars, njobs) );
1252 
1253  /* create for each job a start time variable */
1254  for( v = 0; v < njobs; ++v )
1255  {
1256  SCIP_Real objval;
1257 
1258  /* construct varibale name */
1259  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
1260 
1261  if( objvals == NULL )
1262  objval = 0.0;
1263  else
1264  objval = objvals[v];
1265 
1266  SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
1267  SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
1268  }
1269 
1270  /* create cumulative constraint */
1271  SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
1272  njobs, subvars, durations, demands, capacity) );
1273 
1274  /* set effective horizon */
1275  SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
1276  SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
1277 
1278  /* add cumulative constraint */
1279  SCIP_CALL( SCIPaddCons(subscip, cons) );
1280  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1281 
1282  /* set CP solver settings
1283  *
1284  * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
1285  * time limit.
1286  */
1288 
1289  /* do not abort subproblem on CTRL-C */
1290  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1291 
1292  /* disable output to console */
1293  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1294 
1295  /* set limits for the subproblem */
1296  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1297  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1298  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1299 
1300  /* forbid recursive call of heuristics and separators solving subMIPs
1301  * todo: really? This method was part of 3.0.1 but not in v31-Bugfix
1302  */
1303  SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
1304 
1305  /* solve single cumulative constraint by branch and bound */
1306  retcode = SCIPsolve(subscip);
1307 
1308  if( retcode != SCIP_OKAY )
1309  (*error) = TRUE;
1310  else
1311  {
1312  SCIPdebugMessage("solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1313 
1314  /* evaluated solution status */
1315  switch( SCIPgetStatus(subscip) )
1316  {
1317  case SCIP_STATUS_INFORUNBD:
1319  (*infeasible) = TRUE;
1320  (*solved) = TRUE;
1321  break;
1322  case SCIP_STATUS_UNBOUNDED:
1323  (*unbounded) = TRUE;
1324  (*solved) = TRUE;
1325  break;
1326  case SCIP_STATUS_OPTIMAL:
1327  {
1328  SCIP_SOL* sol;
1329  SCIP_Real solval;
1330 
1331  sol = SCIPgetBestSol(subscip);
1332  assert(sol != NULL);
1333 
1334  for( v = 0; v < njobs; ++v )
1335  {
1336  solval = SCIPgetSolVal(subscip, sol, subvars[v]);
1337 
1338  ests[v] = solval;
1339  lsts[v] = solval;
1340  }
1341  (*solved) = TRUE;
1342  break;
1343  }
1344  case SCIP_STATUS_NODELIMIT:
1346  case SCIP_STATUS_TIMELIMIT:
1347  case SCIP_STATUS_MEMLIMIT:
1349  /* transfer the global bound changes */
1350  for( v = 0; v < njobs; ++v )
1351  {
1352  ests[v] = SCIPvarGetLbGlobal(subvars[v]);
1353  lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
1354  }
1355  (*solved) = FALSE;
1356  break;
1357 
1358  case SCIP_STATUS_UNKNOWN:
1360  case SCIP_STATUS_GAPLIMIT:
1361  case SCIP_STATUS_SOLLIMIT:
1364  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1365  return SCIP_INVALIDDATA;
1366  }
1367  }
1368 
1369  /* release all variables */
1370  for( v = 0; v < njobs; ++v )
1371  {
1372  SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1373  }
1374 
1375  SCIPfreeMemoryArray(subscip, &subvars);
1376 
1377  SCIP_CALL( SCIPfree(&subscip) );
1378 
1379  return SCIP_OKAY;
1380 }
1381 
1382 #if 0
1383 /** solve single cumulative condition using SCIP and the time indexed formulation */
1384 static
1385 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1386 {
1387  SCIP* subscip;
1388  SCIP_VAR*** binvars;
1389  SCIP_RETCODE retcode;
1390  char name[SCIP_MAXSTRLEN];
1391  int minest;
1392  int maxlct;
1393  int t;
1394  int v;
1395 
1396  assert(njobs > 0);
1397 
1398  (*solved) = FALSE;
1399  (*infeasible) = FALSE;
1400  (*unbounded) = FALSE;
1401  (*error) = FALSE;
1402 
1403  SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1404 
1405  /* initialize the sub-problem */
1406  SCIP_CALL( SCIPcreate(&subscip) );
1407 
1408  /* copy all plugins */
1410 
1411  /* create the subproblem */
1412  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1413 
1414  SCIP_CALL( SCIPallocMemoryArray(subscip, &binvars, njobs) );
1415 
1416  minest = INT_MAX;
1417  maxlct = INT_MIN;
1418 
1419  /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1420  * partitioning constrain which forces that job starts
1421  */
1422  for( v = 0; v < njobs; ++v )
1423  {
1424  SCIP_CONS* cons;
1425  SCIP_Real objval;
1426  int timeinterval;
1427  int est;
1428  int lst;
1429 
1430  if( objvals == NULL )
1431  objval = 0.0;
1432  else
1433  objval = objvals[v];
1434 
1435  est = ests[v];
1436  lst = lsts[v];
1437 
1438  /* compute number of possible start points */
1439  timeinterval = lst - est + 1;
1440  assert(timeinterval > 0);
1441 
1442  /* compute the smallest earliest start time and largest latest completion time */
1443  minest = MIN(minest, est);
1444  maxlct = MAX(maxlct, lst + durations[v]);
1445 
1446  /* construct constraint name */
1447  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1448 
1449  SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1450 
1451  SCIP_CALL( SCIPallocMemoryArray(subscip, &binvars[v], timeinterval) );
1452 
1453  for( t = 0; t < timeinterval; ++t )
1454  {
1455  SCIP_VAR* binvar;
1456 
1457  /* construct varibale name */
1458  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1459 
1460  SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1461  SCIP_CALL( SCIPaddVar(subscip, binvar) );
1462 
1463  /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1464  SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1465 
1466  binvars[v][t] = binvar;
1467  }
1468 
1469  /* add and release the set partitioning constraint */
1470  SCIP_CALL( SCIPaddCons(subscip, cons) );
1471  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1472  }
1473 
1474  /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1475  hmin = MAX(hmin, minest);
1476  hmax = MIN(hmax, maxlct);
1477  assert(hmin > INT_MIN);
1478  assert(hmax < INT_MAX);
1479  assert(hmin < hmax);
1480 
1481  /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1482  for( t = hmin; t < hmax; ++t )
1483  {
1484  SCIP_CONS* cons;
1485 
1486  /* construct constraint name */
1487  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1488 
1489  /* create an empty knapsack constraint */
1490  SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1491 
1492  /* add all jobs which potentially can be processed at that time point */
1493  for( v = 0; v < njobs; ++v )
1494  {
1495  int duration;
1496  int demand;
1497  int start;
1498  int end;
1499  int est;
1500  int lst;
1501  int k;
1502 
1503  est = ests[v];
1504  lst = lsts[v] ;
1505 
1506  duration = durations[v];
1507  assert(duration > 0);
1508 
1509  /* check if the varibale is processed potentially at time point t */
1510  if( t < est || t >= lst + duration )
1511  continue;
1512 
1513  demand = demands[v];
1514  assert(demand >= 0);
1515 
1516  start = MAX(t - duration + 1, est);
1517  end = MIN(t, lst);
1518 
1519  assert(start <= end);
1520 
1521  for( k = start; k <= end; ++k )
1522  {
1523  assert(binvars[v][k] != NULL);
1524  SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1525  }
1526  }
1527 
1528  /* add and release the knapsack constraint */
1529  SCIP_CALL( SCIPaddCons(subscip, cons) );
1530  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1531  }
1532 
1533  /* do not abort subproblem on CTRL-C */
1534  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1535 
1536  /* disable output to console */
1537  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1538 
1539  /* set limits for the subproblem */
1540  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1541  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1542  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1543 
1544  /* solve single cumulative constraint by branch and bound */
1545  retcode = SCIPsolve(subscip);
1546 
1547  if( retcode != SCIP_OKAY )
1548  (*error) = TRUE;
1549  else
1550  {
1551  SCIPdebugMessage("solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1552 
1553  /* evaluated solution status */
1554  switch( SCIPgetStatus(subscip) )
1555  {
1556  case SCIP_STATUS_INFORUNBD:
1558  (*infeasible) = TRUE;
1559  (*solved) = TRUE;
1560  break;
1561  case SCIP_STATUS_UNBOUNDED:
1562  (*unbounded) = TRUE;
1563  (*solved) = TRUE;
1564  break;
1565  case SCIP_STATUS_OPTIMAL:
1566  {
1567  SCIP_SOL* sol;
1568 
1569  sol = SCIPgetBestSol(subscip);
1570  assert(sol != NULL);
1571 
1572  for( v = 0; v < njobs; ++v )
1573  {
1574  int timeinterval;
1575  int est;
1576  int lst;
1577 
1578  est = ests[v];
1579  lst = lsts[v];
1580 
1581  /* compute number of possible start points */
1582  timeinterval = lst - est + 1;
1583 
1584  /* check which binary varibale is set to one */
1585  for( t = 0; t < timeinterval; ++t )
1586  {
1587  if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1588  {
1589  ests[v] = est + t;
1590  lsts[v] = est + t;
1591  break;
1592  }
1593  }
1594  }
1595 
1596  (*solved) = TRUE;
1597  break;
1598  }
1599  case SCIP_STATUS_NODELIMIT:
1601  case SCIP_STATUS_TIMELIMIT:
1602  case SCIP_STATUS_MEMLIMIT:
1604  /* transfer the global bound changes */
1605  for( v = 0; v < njobs; ++v )
1606  {
1607  int timeinterval;
1608  int est;
1609  int lst;
1610 
1611  est = ests[v];
1612  lst = lsts[v];
1613 
1614  /* compute number of possible start points */
1615  timeinterval = lst - est + 1;
1616 
1617  /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1618  for( t = 0; t < timeinterval; ++t )
1619  {
1620  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1621  {
1622  ests[v] = est + t;
1623  break;
1624  }
1625  }
1626 
1627  /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1628  for( t = timeinterval - 1; t >= 0; --t )
1629  {
1630  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1631  {
1632  lsts[v] = est + t;
1633  break;
1634  }
1635  }
1636  }
1637  (*solved) = FALSE;
1638  break;
1639 
1640  case SCIP_STATUS_UNKNOWN:
1642  case SCIP_STATUS_GAPLIMIT:
1643  case SCIP_STATUS_SOLLIMIT:
1645  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1646  return SCIP_INVALIDDATA;
1647  }
1648  }
1649 
1650  /* release all variables */
1651  for( v = 0; v < njobs; ++v )
1652  {
1653  int timeinterval;
1654  int est;
1655  int lst;
1656 
1657  est = ests[v];
1658  lst = lsts[v];
1659 
1660  /* compute number of possible start points */
1661  timeinterval = lst - est + 1;
1662 
1663  for( t = 0; t < timeinterval; ++t )
1664  {
1665  SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1666  }
1667  SCIPfreeMemoryArray(subscip, &binvars[v]);
1668  }
1669 
1670  SCIPfreeMemoryArray(subscip, &binvars);
1671 
1672  SCIP_CALL( SCIPfree(&subscip) );
1673 
1674  return SCIP_OKAY;
1675 }
1676 #endif
1677 
1678 /**@} */
1679 
1680 /**@name Constraint handler data
1681  *
1682  * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1683  * handler.
1684  *
1685  * @{
1686  */
1687 
1688 /** creates constaint handler data for cumulative constraint handler */
1689 static
1691  SCIP* scip, /**< SCIP data structure */
1692  SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1693  SCIP_EVENTHDLR* eventhdlr /**< event handler */
1694  )
1695 {
1696  /* create precedence constraint handler data */
1697  assert(scip != NULL);
1698  assert(conshdlrdata != NULL);
1699  assert(eventhdlr != NULL);
1700 
1701  SCIP_CALL( SCIPallocMemory(scip, conshdlrdata) );
1702 
1703  /* set event handler for checking if bounds of start time variables are tighten */
1704  (*conshdlrdata)->eventhdlr = eventhdlr;
1705 
1706  /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1707  (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1708 
1709 #ifdef SCIP_STATISTIC
1710  (*conshdlrdata)->nlbtimetable = 0;
1711  (*conshdlrdata)->nubtimetable = 0;
1712  (*conshdlrdata)->ncutofftimetable = 0;
1713  (*conshdlrdata)->nlbedgefinder = 0;
1714  (*conshdlrdata)->nubedgefinder = 0;
1715  (*conshdlrdata)->ncutoffedgefinder = 0;
1716  (*conshdlrdata)->ncutoffoverload = 0;
1717  (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1718 
1719  (*conshdlrdata)->nirrelevantjobs = 0;
1720  (*conshdlrdata)->nalwaysruns = 0;
1721  (*conshdlrdata)->nremovedlocks = 0;
1722  (*conshdlrdata)->ndualfixs = 0;
1723  (*conshdlrdata)->ndecomps = 0;
1724  (*conshdlrdata)->ndualbranchs = 0;
1725  (*conshdlrdata)->nallconsdualfixs = 0;
1726  (*conshdlrdata)->naddedvarbounds = 0;
1727  (*conshdlrdata)->naddeddisjunctives = 0;
1728 #endif
1729 
1730  return SCIP_OKAY;
1731 }
1732 
1733 /** frees constraint handler data for logic or constraint handler */
1734 static
1735 void conshdlrdataFree(
1736  SCIP* scip, /**< SCIP data structure */
1737  SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1738  )
1739 {
1740  assert(conshdlrdata != NULL);
1741  assert(*conshdlrdata != NULL);
1742 
1743  SCIPfreeMemory(scip, conshdlrdata);
1744 }
1745 
1746 /**@} */
1747 
1748 
1749 /**@name Constraint data methods
1750  *
1751  * @{
1752  */
1753 
1754 /** catches bound change events for all variables in transformed cumulative constraint */
1755 static
1757  SCIP* scip, /**< SCIP data structure */
1758  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1759  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1760  )
1761 {
1762  int v;
1763 
1764  assert(scip != NULL);
1765  assert(consdata != NULL);
1766  assert(eventhdlr != NULL);
1767 
1768  /* catch event for every single variable */
1769  for( v = 0; v < consdata->nvars; ++v )
1770  {
1771  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1772  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1773  }
1774 
1775  return SCIP_OKAY;
1776 }
1777 
1778 /** drops events for variable at given position */
1779 static
1781  SCIP* scip, /**< SCIP data structure */
1782  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1783  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1784  int pos /**< array position of variable to catch bound change events for */
1785  )
1786 {
1787  assert(scip != NULL);
1788  assert(consdata != NULL);
1789  assert(eventhdlr != NULL);
1790  assert(0 <= pos && pos < consdata->nvars);
1791  assert(consdata->vars[pos] != NULL);
1792 
1793  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1794  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1795 
1796  return SCIP_OKAY;
1797 }
1798 
1799 /** drops bound change events for all variables in transformed linear constraint */
1800 static
1802  SCIP* scip, /**< SCIP data structure */
1803  SCIP_CONSDATA* consdata, /**< linear constraint data */
1804  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1805  )
1806 {
1807  int v;
1808 
1809  assert(scip != NULL);
1810  assert(consdata != NULL);
1811 
1812  /* drop event of every single variable */
1813  for( v = 0; v < consdata->nvars; ++v )
1814  {
1815  SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1816  }
1817 
1818  return SCIP_OKAY;
1819 }
1820 
1821 /** initialize variable lock data structure */
1822 static
1823 void initializeLocks(
1824  SCIP_CONSDATA* consdata, /**< constraint data */
1825  SCIP_Bool locked /**< should the variable be locked? */
1826  )
1827 {
1828  int nvars;
1829  int v;
1830 
1831  nvars = consdata->nvars;
1832 
1833  /* initialize locking arrays */
1834  for( v = 0; v < nvars; ++v )
1835  {
1836  consdata->downlocks[v] = locked;
1837  consdata->uplocks[v] = locked;
1838  }
1839 }
1840 
1841 /** creates constraint data of cumulative constraint */
1842 static
1844  SCIP* scip, /**< SCIP data structure */
1845  SCIP_CONSDATA** consdata, /**< pointer to consdata */
1846  SCIP_VAR** vars, /**< array of integer variables */
1847  SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1848  int* durations, /**< array containing corresponding durations */
1849  int* demands, /**< array containing corresponding demands */
1850  int nvars, /**< number of variables */
1851  int capacity, /**< available cumulative capacity */
1852  int hmin, /**< left bound of time axis to be considered (including hmin) */
1853  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1854  SCIP_Bool check /**< is the corresponding constraint a check constraint */
1855  )
1856 {
1857  int v;
1858 
1859  assert(scip != NULL);
1860  assert(consdata != NULL);
1861  assert(vars != NULL || nvars > 0);
1862  assert(demands != NULL);
1863  assert(durations != NULL);
1864  assert(capacity >= 0);
1865  assert(hmin >= 0);
1866  assert(hmin < hmax);
1867 
1868  /* create constraint data */
1869  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1870 
1871  (*consdata)->hmin = hmin;
1872  (*consdata)->hmax = hmax;
1873 
1874  (*consdata)->capacity = capacity;
1875  (*consdata)->demandrows = NULL;
1876  (*consdata)->demandrowssize = 0;
1877  (*consdata)->ndemandrows = 0;
1878  (*consdata)->scoverrows = NULL;
1879  (*consdata)->nscoverrows = 0;
1880  (*consdata)->scoverrowssize = 0;
1881  (*consdata)->bcoverrows = NULL;
1882  (*consdata)->nbcoverrows = 0;
1883  (*consdata)->bcoverrowssize = 0;
1884  (*consdata)->nvars = nvars;
1885  (*consdata)->varssize = nvars;
1886  (*consdata)->signature = 0;
1887  (*consdata)->validsignature = FALSE;
1888  (*consdata)->normalized = FALSE;
1889  (*consdata)->covercuts = FALSE;
1890  (*consdata)->propagated = FALSE;
1891  (*consdata)->varbounds = FALSE;
1892  (*consdata)->triedsolving = FALSE;
1893 
1894  if( nvars > 0 )
1895  {
1896  assert(vars != NULL); /* for flexelint */
1897 
1898  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1899  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1900  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1901  (*consdata)->linkingconss = NULL;
1902 
1903  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1904  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1905 
1906  /* initialize variable lock data structure; the locks are only used if the contraint is a check constraint */
1907  initializeLocks(*consdata, check);
1908 
1909  if( linkingconss != NULL )
1910  {
1911  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
1912  }
1913 
1914  /* transform variables, if they are not yet transformed */
1915  if( SCIPisTransformed(scip) )
1916  {
1917  SCIPdebugMessage("get tranformed variables and constraints\n");
1918 
1919  /* get transformed variables and do NOT captures these */
1920  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1921 
1922  /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
1923  * been multi-aggregated
1924  */
1925  for( v = 0; v < nvars; ++v )
1926  {
1927  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
1928  }
1929 
1930  if( linkingconss != NULL )
1931  {
1932  /* get transformed constraints and captures these */
1933  SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
1934 
1935  for( v = 0; v < nvars; ++v )
1936  assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
1937  }
1938  }
1939  }
1940  else
1941  {
1942  (*consdata)->vars = NULL;
1943  (*consdata)->downlocks = NULL;
1944  (*consdata)->uplocks = NULL;
1945  (*consdata)->demands = NULL;
1946  (*consdata)->durations = NULL;
1947  (*consdata)->linkingconss = NULL;
1948  }
1949 
1950  /* initialize values for running propagation algorithms efficiently */
1951  (*consdata)->resstrength1 = -1.0;
1952  (*consdata)->resstrength2 = -1.0;
1953  (*consdata)->cumfactor1 = -1.0;
1954  (*consdata)->disjfactor1 = -1.0;
1955  (*consdata)->disjfactor2 = -1.0;
1956  (*consdata)->estimatedstrength = -1.0;
1957 
1958  SCIPstatistic( (*consdata)->maxpeak = -1 );
1959 
1960  return SCIP_OKAY;
1961 }
1962 
1963 /** releases LP rows of constraint data and frees rows array */
1964 static
1966  SCIP* scip, /**< SCIP data structure */
1967  SCIP_CONSDATA** consdata /**< constraint data */
1968  )
1969 {
1970  int r;
1971 
1972  assert(consdata != NULL);
1973  assert(*consdata != NULL);
1974 
1975  for( r = 0; r < (*consdata)->ndemandrows; ++r )
1976  {
1977  assert((*consdata)->demandrows[r] != NULL);
1978  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
1979  }
1980 
1981  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
1982 
1983  (*consdata)->ndemandrows = 0;
1984  (*consdata)->demandrowssize = 0;
1985 
1986  /* free rows of cover cuts */
1987  for( r = 0; r < (*consdata)->nscoverrows; ++r )
1988  {
1989  assert((*consdata)->scoverrows[r] != NULL);
1990  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
1991  }
1992 
1993  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
1994 
1995  (*consdata)->nscoverrows = 0;
1996  (*consdata)->scoverrowssize = 0;
1997 
1998  for( r = 0; r < (*consdata)->nbcoverrows; ++r )
1999  {
2000  assert((*consdata)->bcoverrows[r] != NULL);
2001  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2002  }
2003 
2004  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2005 
2006  (*consdata)->nbcoverrows = 0;
2007  (*consdata)->bcoverrowssize = 0;
2008 
2009  (*consdata)->covercuts = FALSE;
2010 
2011  return SCIP_OKAY;
2012 }
2013 
2014 /** frees a cumulative constraint data */
2015 static
2017  SCIP* scip, /**< SCIP data structure */
2018  SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2019  )
2020 {
2021  int varssize;
2022  int nvars;
2023 
2024  assert(consdata != NULL);
2025  assert(*consdata != NULL);
2026 
2027  nvars = (*consdata)->nvars;
2028  varssize = (*consdata)->varssize;
2029 
2030  if( varssize > 0 )
2031  {
2032  int v;
2033 
2034  /* release and free the rows */
2035  SCIP_CALL( consdataFreeRows(scip, consdata) );
2036 
2037  /* release the linking constraints if they were generated */
2038  if( (*consdata)->linkingconss != NULL )
2039  {
2040  for( v = nvars-1; v >= 0; --v )
2041  {
2042  assert((*consdata)->linkingconss[v] != NULL );
2043  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2044  }
2045 
2046  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2047  }
2048 
2049  /* free arrays */
2050  SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2051  SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2052  SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2053  SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2054  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2055  }
2056 
2057  /* free memory */
2058  SCIPfreeBlockMemory(scip, consdata);
2059 
2060  return SCIP_OKAY;
2061 }
2062 
2063 /** prints cumulative constraint to file stream */
2064 static
2065 void consdataPrint(
2066  SCIP* scip, /**< SCIP data structure */
2067  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2068  FILE* file /**< output file (or NULL for standard output) */
2069  )
2070 {
2071  int v;
2072 
2073  assert(consdata != NULL);
2074 
2075  /* print coefficients */
2076  SCIPinfoMessage( scip, file, "cumulative(");
2077 
2078  for( v = 0; v < consdata->nvars; ++v )
2079  {
2080  assert(consdata->vars[v] != NULL);
2081  if( v > 0 )
2082  SCIPinfoMessage(scip, file, ", ");
2083  SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2084  SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2085  consdata->durations[v], consdata->demands[v]);
2086  }
2087  SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2088 }
2089 
2090 /** deletes coefficient at given position from constraint data */
2091 static
2093  SCIP* scip, /**< SCIP data structure */
2094  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2095  SCIP_CONS* cons, /**< knapsack constraint */
2096  int pos /**< position of coefficient to delete */
2097  )
2098 {
2099  SCIP_CONSHDLR* conshdlr;
2100  SCIP_CONSHDLRDATA* conshdlrdata;
2101 
2102  assert(scip != NULL);
2103  assert(consdata != NULL);
2104  assert(cons != NULL);
2105  assert(SCIPconsIsTransformed(cons));
2106  assert(!SCIPinProbing(scip));
2107 
2108  SCIPdebugMessage("cumulative constraint <%s>: remove variable <%s>\n",
2109  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2110 
2111  /* remove the rounding locks for the deleted variable */
2112  SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2113 
2114  consdata->downlocks[pos] = FALSE;
2115  consdata->uplocks[pos] = FALSE;
2116 
2117  if( consdata->linkingconss != NULL )
2118  {
2119  SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2120  }
2121 
2122  /* get event handler */
2123  conshdlr = SCIPconsGetHdlr(cons);
2124  assert(conshdlr != NULL);
2125  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2126  assert(conshdlrdata != NULL);
2127  assert(conshdlrdata->eventhdlr != NULL);
2128 
2129  /* drop events */
2130  SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2131 
2132  SCIPdebugMessage("remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2133  SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2134 
2135 
2136  /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2137  * position
2138  */
2139  if( pos != consdata->nvars - 1 )
2140  {
2141  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2142  consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2143  consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2144  consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2145  consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2146 
2147  if( consdata->linkingconss != NULL )
2148  {
2149  consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2150  }
2151  }
2152 
2153  consdata->nvars--;
2154  consdata->validsignature = FALSE;
2155  consdata->normalized = FALSE;
2156 
2157  return SCIP_OKAY;
2158 }
2159 
2160 /** collect linking constraints for each integer variable */
2161 static
2163  SCIP* scip, /**< SCIP data structure */
2164  SCIP_CONSDATA* consdata /**< pointer to consdata */
2165  )
2166 {
2167  int nvars;
2168  int v;
2169 
2170  assert(scip != NULL);
2171  assert(consdata != NULL);
2172 
2173  nvars = consdata->nvars;
2174  assert(nvars > 0);
2175  assert(consdata->linkingconss == NULL);
2176 
2177  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2178 
2179  for( v = 0; v < nvars; ++v )
2180  {
2181  SCIP_CONS* cons;
2182  SCIP_VAR* var;
2183 
2184  var = consdata->vars[v];
2185  assert(var != NULL);
2186 
2187  SCIPdebugMessage("linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2188 
2189  /* create linking constraint if it does not exist yet */
2190  if( !SCIPexistsConsLinking(scip, var) )
2191  {
2192  char name[SCIP_MAXSTRLEN];
2193 
2194  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2195 
2196  /* creates and captures an linking constraint */
2197  SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2198  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2199  SCIP_CALL( SCIPaddCons(scip, cons) );
2200  consdata->linkingconss[v] = cons;
2201  }
2202  else
2203  {
2204  consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2205  SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2206  }
2207 
2208  assert(SCIPexistsConsLinking(scip, var));
2209  assert(consdata->linkingconss[v] != NULL);
2210  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2211  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2212  }
2213 
2214  return SCIP_OKAY;
2215 }
2216 
2217 /**@} */
2218 
2219 
2220 /**@name Check methods
2221  *
2222  * @{
2223  */
2224 
2225 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2226  * given solution is satisfied
2227  */
2228 static
2230  SCIP* scip, /**< SCIP data structure */
2231  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2232  int nvars, /**< number of variables (jobs) */
2233  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2234  int* durations, /**< array containing corresponding durations */
2235  int* demands, /**< array containing corresponding demands */
2236  int capacity, /**< available cumulative capacity */
2237  int hmin, /**< left bound of time axis to be considered (including hmin) */
2238  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2239  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2240  SCIP_CONS* cons, /**< constraint which is checked */
2241  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2242  )
2243 {
2244  int* startsolvalues; /* stores when each job is starting */
2245  int* endsolvalues; /* stores when each job ends */
2246  int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2247  int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2248 
2249  int freecapacity;
2250  int curtime; /* point in time which we are just checking */
2251  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2252  int j;
2253 
2254  assert(scip != NULL);
2255  assert(violated != NULL);
2256 
2257  (*violated) = FALSE;
2258 
2259  if( nvars == 0 )
2260  return SCIP_OKAY;
2261 
2262  assert(vars != NULL);
2263  assert(demands != NULL);
2264  assert(durations != NULL);
2265 
2266  /* compute time points where we have to check whether capacity constraint is infeasible or not */
2267  SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2268  SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2269  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2270  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2271 
2272  /* assign variables, start and endpoints to arrays */
2273  for ( j = 0; j < nvars; ++j )
2274  {
2275  int solvalue;
2276 
2277  /* the constraint of the cumulative constraint handler should be called after the integrality check */
2278  assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2279 
2280  solvalue = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2281 
2282  /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2283  * jobs which start before hmin to hmin
2284  */
2285  startsolvalues[j] = MAX(solvalue, hmin);
2286  startindices[j] = j;
2287 
2288  endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2289  endindices[j] = j;
2290  }
2291 
2292  /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2293  * corresponding indices in the same way)
2294  */
2295  SCIPsortIntInt(startsolvalues, startindices, nvars);
2296  SCIPsortIntInt(endsolvalues, endindices, nvars);
2297 
2298  endindex = 0;
2299  freecapacity = capacity;
2300 
2301  /* check each start point of a job whether the capacity is kept or not */
2302  for( j = 0; j < nvars; ++j )
2303  {
2304  /* only check intervals [hmin,hmax) */
2305  curtime = startsolvalues[j];
2306 
2307  if( curtime >= hmax )
2308  break;
2309 
2310  /* subtract all capacity needed up to this point */
2311  freecapacity -= demands[startindices[j]];
2312  while( j+1 < nvars && startsolvalues[j+1] == curtime )
2313  {
2314  j++;
2315  freecapacity -= demands[startindices[j]];
2316  }
2317 
2318  /* free all capacity usages of jobs that are no longer running */
2319  while( endindex < nvars && curtime >= endsolvalues[endindex] )
2320  {
2321  freecapacity += demands[endindices[endindex]];
2322  ++endindex;
2323  }
2324  assert(freecapacity <= capacity);
2325 
2326  /* check freecapacity to be smaller than zero */
2327  if( freecapacity < 0 && curtime >= hmin )
2328  {
2329  SCIPdebugMessage("freecapacity = %3d\n", freecapacity);
2330  (*violated) = TRUE;
2331 
2332  if( printreason )
2333  {
2334  int i;
2335 
2336  /* first state the violated constraints */
2337  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2338 
2339  /* second state the reason */
2340  SCIPinfoMessage(scip, NULL,
2341  ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2342  curtime, capacity, capacity - freecapacity);
2343 
2344  for( i = 0; i <= j; ++i )
2345  {
2346  if( startsolvalues[i] + durations[startindices[i]] > curtime )
2347  {
2348  SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2349  SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2350  demands[startindices[i]]);
2351  }
2352  }
2353  }
2354  break;
2355  }
2356  } /*lint --e{850}*/
2357 
2358  /* free all buffer arrays */
2359  SCIPfreeBufferArray(scip, &endindices);
2360  SCIPfreeBufferArray(scip, &startindices);
2361  SCIPfreeBufferArray(scip, &endsolvalues);
2362  SCIPfreeBufferArray(scip, &startsolvalues);
2363 
2364  return SCIP_OKAY;
2365 }
2366 
2367 /** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2368  * least zero or not. If not (*violated) is set to TRUE
2369  */
2370 static
2372  SCIP* scip, /**< SCIP data structure */
2373  SCIP_CONS* cons, /**< constraint to be checked */
2374  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2375  SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2376  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2377  )
2378 {
2379  SCIP_CONSDATA* consdata;
2380 
2381  assert(scip != NULL);
2382  assert(cons != NULL);
2383  assert(violated != NULL);
2384 
2385  SCIPdebugMessage("check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2386 
2387  consdata = SCIPconsGetData(cons);
2388  assert(consdata != NULL);
2389 
2390  /* check the cumulative condition */
2391  SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2392  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2393  violated, cons, printreason) );
2394 
2395  return SCIP_OKAY;
2396 }
2397 
2398 /**@} */
2399 
2400 /**@name Conflict analysis
2401  *
2402  * @{
2403  */
2404 
2405 /** resolves the propagation of the core time algorithm */
2406 static
2408  SCIP* scip, /**< SCIP data structure */
2409  int nvars, /**< number of start time variables (activities) */
2410  SCIP_VAR** vars, /**< array of start time variables */
2411  int* durations, /**< array of durations */
2412  int* demands, /**< array of demands */
2413  int capacity, /**< cumulative capacity */
2414  int hmin, /**< left bound of time axis to be considered (including hmin) */
2415  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2416  SCIP_VAR* infervar, /**< inference variable */
2417  int inferdemand, /**< demand of the inference variable */
2418  int inferpeak, /**< time point which causes the propagation */
2419  int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2420  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2421  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2422  int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2423  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2424  )
2425 {
2426  SCIP_VAR* var;
2427  SCIP_Bool* reported;
2428  int duration;
2429  int maxlst;
2430  int minect;
2431  int ect;
2432  int lst;
2433  int j;
2434 
2435  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
2436 
2437  SCIPdebugMessage("variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2438  SCIPvarGetName(infervar), inferdemand, inferpeak);
2439  assert(nvars > 0);
2440 
2441  /* adjusted capacity */
2442  capacity -= inferdemand;
2443  maxlst = INT_MIN;
2444  minect = INT_MAX;
2445 
2446  SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2447  BMSclearMemoryArray(reported, nvars);
2448 
2449  /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2450  * inference peak and those where the current conflict bounds provide a core at the inference peak
2451  */
2452  for( j = 0; j < nvars && capacity >= 0; ++j )
2453  {
2454  var = vars[j];
2455  assert(var != NULL);
2456 
2457  /* skip inference variable */
2458  if( var == infervar )
2459  continue;
2460 
2461  duration = durations[j];
2462  assert(duration > 0);
2463 
2464  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2465  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPvarGetUbAtIndex(var, bdchgidx, TRUE), SCIPvarGetUbAtIndex(var, bdchgidx, FALSE)));
2466  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbAtIndex(var, bdchgidx, TRUE)));
2467  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPvarGetLbAtIndex(var, bdchgidx, TRUE), SCIPvarGetLbAtIndex(var, bdchgidx, FALSE)));
2468  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbAtIndex(var, bdchgidx, TRUE)));
2469 
2470  SCIPdebugMessage("variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2472  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2473 
2474  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2475  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2476 
2477  /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2478  * that job without adding it the explanation
2479  */
2480  if( inferpeak < ect && lst <= inferpeak )
2481  {
2482  capacity -= demands[j];
2483  reported[j] = TRUE;
2484 
2485  maxlst = MAX(maxlst, lst);
2486  minect = MIN(minect, ect);
2487  assert(maxlst < minect);
2488 
2489  if( explanation != NULL )
2490  explanation[j] = TRUE;
2491 
2492  continue;
2493  }
2494 
2495  /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2496  * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2497  * not part of the conflict yet we get the global bounds back.
2498  */
2499  ect = SCIPconvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2500  lst = SCIPconvertRealToInt(scip, SCIPgetConflictVarUb(scip, var));
2501 
2502  /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2503  * of that job without and collect the job as part of the explanation
2504  *
2505  * @note we do not need to reported that job to SCIP since the required bounds are already reported
2506  */
2507  if( inferpeak < ect && lst <= inferpeak )
2508  {
2509  capacity -= demands[j];
2510  reported[j] = TRUE;
2511 
2512  maxlst = MAX(maxlst, lst);
2513  minect = MIN(minect, ect);
2514  assert(maxlst < minect);
2515 
2516  if( explanation != NULL )
2517  explanation[j] = TRUE;
2518  }
2519  }
2520 
2521  if( capacity >= 0 )
2522  {
2523  int* cands;
2524  int* canddemands;
2525  int ncands;
2526  int c;
2527 
2528  SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2529  SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2530  ncands = 0;
2531 
2532  /* collect all cores of the variables which lay in the considered time window except the inference variable */
2533  for( j = 0; j < nvars; ++j )
2534  {
2535  var = vars[j];
2536  assert(var != NULL);
2537 
2538  /* skip inference variable */
2539  if( var == infervar || reported[j] )
2540  continue;
2541 
2542  duration = durations[j];
2543  assert(duration > 0);
2544 
2545  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2546  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPvarGetUbAtIndex(var, bdchgidx, TRUE), SCIPvarGetUbAtIndex(var, bdchgidx, FALSE)));
2547  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbAtIndex(var, bdchgidx, TRUE)));
2548  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPvarGetLbAtIndex(var, bdchgidx, TRUE), SCIPvarGetLbAtIndex(var, bdchgidx, FALSE)));
2549  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbAtIndex(var, bdchgidx, TRUE)));
2550 
2551  /* collect local core information */
2552  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbAtIndex(var, bdchgidx, FALSE)) + duration;
2553  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(var, bdchgidx, FALSE));
2554 
2555  SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2556  SCIPvarGetName(var), SCIPvarGetLbAtIndex(var, bdchgidx, FALSE), SCIPvarGetUbAtIndex(var, bdchgidx, FALSE),
2557  SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2558 
2559  /* check if the inference peak is part of the core */
2560  if( inferpeak < ect && lst <= inferpeak )
2561  {
2562  cands[ncands] = j;
2563  canddemands[ncands] = demands[j];
2564  ncands++;
2565 
2566  capacity -= demands[j];
2567  }
2568  }
2569 
2570  /* sort candidates indices w.r.t. their demands */
2571  SCIPsortDownIntInt(canddemands, cands, ncands);
2572 
2573  assert(capacity < 0);
2574  assert(ncands > 0);
2575 
2576  /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2577  while( capacity + canddemands[ncands-1] < 0 )
2578  {
2579  ncands--;
2580  capacity += canddemands[ncands];
2581  assert(ncands > 0);
2582  }
2583 
2584  /* compute the size (number of time steps) of the job cores */
2585  for( c = 0; c < ncands; ++c )
2586  {
2587  var = vars[cands[c]];
2588  assert(var != NULL);
2589 
2590  duration = durations[cands[c]];
2591 
2592  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbAtIndex(var, bdchgidx, FALSE)) + duration;
2593  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(var, bdchgidx, FALSE));
2594 
2595  maxlst = MAX(maxlst, lst);
2596  minect = MIN(minect, ect);
2597  assert(maxlst < minect);
2598  }
2599 
2600  SCIPdebugMessage("infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2601  assert(inferpeak >= maxlst);
2602  assert(inferpeak < minect);
2603 
2604  /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2605  if( relaxedpeak < inferpeak )
2606  {
2607  inferpeak = MAX(maxlst, relaxedpeak);
2608  }
2609  else if( relaxedpeak > inferpeak )
2610  {
2611  inferpeak = MIN(minect-1, relaxedpeak);
2612  }
2613  assert(inferpeak >= hmin);
2614  assert(inferpeak < hmax);
2615  assert(inferpeak >= maxlst);
2616  assert(inferpeak < minect);
2617 
2618  /* post all necessary bound changes */
2619  for( c = 0; c < ncands; ++c )
2620  {
2621  var = vars[cands[c]];
2622  assert(var != NULL);
2623 
2624  if( usebdwidening )
2625  {
2626  duration = durations[cands[c]];
2627 
2628  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2629  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2630  }
2631  else
2632  {
2633  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2634  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2635  }
2636 
2637  if( explanation != NULL )
2638  explanation[cands[c]] = TRUE;
2639  }
2640 
2641  SCIPfreeBufferArray(scip, &canddemands);
2642  SCIPfreeBufferArray(scip, &cands);
2643  }
2644 
2645  SCIPfreeBufferArray(scip, &reported);
2646 
2647  if( provedpeak != NULL )
2648  *provedpeak = inferpeak;
2649 
2650  return SCIP_OKAY;
2651 }
2652 
2653 #if 0
2654 /** repropagation of edge finding algorithm simplified version from Petr Vilim only a small subset is reported such that
2655  * energy in total and for bound change is enough
2656  */
2657 static
2658 SCIP_RETCODE resolvePropagationEdgeFinding(
2659  SCIP* scip, /**< SCIP data structure */
2660  int nvars, /**< number of start time variables (activities) */
2661  SCIP_VAR** vars, /**< array of start time variables */
2662  int* durations, /**< array of durations */
2663  int hmin, /**< left bound of time axis to be considered (including hmin) */
2664  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2665  SCIP_VAR* infervar, /**< variable whose bound change is to be explained */
2666  INFERINFO inferinfo, /**< inference info containing position of correct bdchgids */
2667  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2668  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2669  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2670  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2671  )
2672 {
2673  int est;
2674  int lct;
2675  int j;
2676 
2677  /* ???????????????????? do bound widening */
2678 
2679  assert(scip != NULL);
2680  assert(nvars > 0);
2681  assert(inferInfoGetProprule(inferinfo) == PROPRULE_2_EDGEFINDING);
2682 
2683  SCIPdebugMessage("repropagate edge-finding with short reasons for variable <%s>\n", SCIPvarGetName(infervar));
2684 
2685  if( boundtype == SCIP_BOUNDTYPE_LOWER )
2686  {
2687  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
2688  }
2689  else
2690  {
2691  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
2692  }
2693 
2694  est = inferInfoGetData1(inferinfo);
2695  lct = inferInfoGetData2(inferinfo);
2696  assert(est < lct);
2697 
2698  /* collect the energies of all variables in [est_omega, lct_omega] */
2699  for( j = 0; j < nvars; ++j )
2700  {
2701  SCIP_VAR* var;
2702  SCIP_Bool left;
2703  SCIP_Bool right;
2704  int duration;
2705  int lb;
2706  int ub;
2707 
2708  var = vars[j];
2709  assert(var != NULL);
2710 
2711  if( var == infervar )
2712  {
2713  if( explanation != NULL )
2714  explanation[j] = TRUE;
2715 
2716  continue;
2717  }
2718 
2719  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbAtIndex(var, bdchgidx, FALSE));
2720  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(var, bdchgidx, FALSE));
2721 
2722  duration = durations[j];
2723  assert(duration > 0);
2724 
2725  /* in case the earliest start time is equal to hmin we have to also consider the jobs which run in that region
2726  * since we use adjusted jobs during the propagation
2727  */
2728  left = (est == hmin && lb + duration > hmin) || lb >= est;
2729 
2730  /* in case the latest completion time is equal to hmax we have to also consider the jobs which run in that region
2731  * since we use adjusted jobs during the propagation
2732  */
2733  right = (lct == hmax && ub < hmax) || ub + duration <= lct;
2734 
2735  /* store all jobs running in [est_omega; lct_omega] */
2736  if( left && right )
2737  {
2738  /* check if bound widening should be used */
2739  if( usebdwidening )
2740  {
2741  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(lct - duration)) );
2742  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(est)) );
2743  }
2744  else
2745  {
2746  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2747  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2748  }
2749 
2750  if( explanation != NULL )
2751  explanation[j] = TRUE;
2752  }
2753  }
2754 
2755  return SCIP_OKAY;
2756 }
2757 #endif
2758 
2759 /** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2760 static
2761 int computeOverlap(
2762  int begin, /**< begin of the times interval */
2763  int end, /**< end of time interval */
2764  int est, /**< earliest start time */
2765  int lst, /**< latest start time */
2766  int duration /**< duration of the job */
2767  )
2768 {
2769  int left;
2770  int right;
2771  int ect;
2772  int lct;
2773 
2774  ect = est + duration;
2775  lct = lst + duration;
2776 
2777  /* check if job runs completely within [begin,end) */
2778  if( lct <= end && est >= begin )
2779  return duration;
2780 
2781  assert(lst <= end && ect >= begin);
2782 
2783  left = ect - begin;
2784  assert(left > 0);
2785 
2786  right = end - lst;
2787  assert(right > 0);
2788 
2789  return MIN3(left, right, end - begin);
2790 }
2791 
2792 /** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2793  * reason
2794  *
2795  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2796  */
2797 static
2799  SCIP* scip, /**< SCIP data structure */
2800  int nvars, /**< number of start time variables (activities) */
2801  SCIP_VAR** vars, /**< array of start time variables */
2802  int* durations, /**< array of durations */
2803  int* demands, /**< array of demands */
2804  int capacity, /**< capacity of the cumulative condition */
2805  int begin, /**< begin of the time window */
2806  int end, /**< end of the time window */
2807  SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2808  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2809  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2810  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2811  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2812  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2813  )
2814 {
2815  int* locenergies;
2816  int* overlaps;
2817  int* idxs;
2818 
2819  int requiredenergy;
2820  int v;
2821 
2822  SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2823  SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2824  SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2825 
2826  /* energy which needs be explained */
2827  requiredenergy = (end - begin) * capacity;
2828 
2829  SCIPdebugMessage("analysis energy load in [%d,%d) (capacity %d, energy %d)\n", begin, end, capacity, requiredenergy);
2830 
2831  /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2832  * takes
2833  */
2834  for( v = 0; v < nvars; ++v )
2835  {
2836  SCIP_VAR* var;
2837  int glbenergy;
2838  int duration;
2839  int demand;
2840  int est;
2841  int lst;
2842 
2843  var = vars[v];
2844  assert(var != NULL);
2845 
2846  locenergies[v] = 0;
2847  overlaps[v] = 0;
2848  idxs[v] = v;
2849 
2850  demand = demands[v];
2851  assert(demand > 0);
2852 
2853  duration = durations[v];
2854  assert(duration > 0);
2855 
2856  /* check if the variable equals the inference variable (the one which was propagated) */
2857  if( infervar == var )
2858  {
2859  int overlap;
2860  int right;
2861  int left;
2862 
2863  assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2864 
2865  SCIPdebugMessage("inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2866  SCIPvarGetName(var), SCIPvarGetLbAtIndex(var, bdchgidx, FALSE), SCIPvarGetUbAtIndex(var, bdchgidx, FALSE),
2867  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2868 
2869  /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2870  * which is necessary from the inference variable
2871  */
2872  if( boundtype == SCIP_BOUNDTYPE_UPPER )
2873  {
2874  int lct;
2875 
2876  /* get the latest start time of the infer start time variable before the propagation took place */
2877  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(var, bdchgidx, FALSE));
2878 
2879  /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2880  * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2881  * scheduled w.r.t. its latest start time
2882  */
2883  assert(lst < end);
2884 
2885  /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2886  * interval (before the propagation)
2887  */
2888  right = MIN3(end - lst, end - begin, duration);
2889 
2890  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2891  assert(right > 0);
2892 
2893  lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2894  assert(begin <= lct);
2895  assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(var, bdchgidx, TRUE)) < begin);
2896 
2897  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2898  left = MIN(lct - begin + 1, end - begin);
2899  assert(left > 0);
2900 
2901  /* compute the minimum overlap; */
2902  overlap = MIN(left, right);
2903  assert(overlap > 0);
2904  assert(overlap <= end - begin);
2905  assert(overlap <= duration);
2906 
2907  if( usebdwidening )
2908  {
2909  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(var, bdchgidx, FALSE)) <= (end - overlap));
2910  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2911  }
2912  else
2913  {
2914  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2915  }
2916  }
2917  else
2918  {
2919  int ect;
2920 
2921  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2922 
2923  /* get the earliest completion time of the infer start time variable before the propagation took place */
2924  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbAtIndex(var, bdchgidx, FALSE)) + duration;
2925 
2926  /* the earliest start time of the inference start time variable before the propagation needs to be larger as
2927  * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
2928  * the job is scheduled w.r.t. its earliest start time
2929  */
2930  assert(ect > begin);
2931 
2932  /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
2933  * interval (before the propagation)
2934  */
2935  left = MIN3(ect - begin, end - begin, duration);
2936 
2937  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2938  assert(left > 0);
2939 
2940  est = SCIPconvertRealToInt(scip, relaxedbd);
2941  assert(end >= est);
2942  assert(bdchgidx == NULL || end - SCIPvarGetLbAtIndex(var, bdchgidx, TRUE) < duration);
2943 
2944  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2945  right = MIN(end - est + 1, end - begin);
2946  assert(right > 0);
2947 
2948  /* compute the minimum overlap */
2949  overlap = MIN(left, right);
2950  assert(overlap > 0);
2951  assert(overlap <= end - begin);
2952  assert(overlap <= duration);
2953 
2954  if( usebdwidening )
2955  {
2956  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbAtIndex(var, bdchgidx, FALSE)) >= (begin + overlap - duration));
2957  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
2958  }
2959  else
2960  {
2961  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2962  }
2963  }
2964 
2965  /* subtract the amount of energy which is available due to the overlap of the inference start time */
2966  requiredenergy -= overlap * demand;
2967 
2968  if( explanation != NULL )
2969  explanation[v] = TRUE;
2970 
2971  continue;
2972  }
2973 
2974  /* global time points */
2975  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
2976  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2977 
2978  glbenergy = 0;
2979 
2980  /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
2981  * time window
2982  */
2983  if( est + duration > begin && lst < end )
2984  {
2985  /* evaluated global contribution */
2986  glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
2987 
2988  /* remove the globally available energy form the required energy */
2989  requiredenergy -= glbenergy;
2990 
2991  if( explanation != NULL )
2992  explanation[v] = TRUE;
2993  }
2994 
2995  /* local time points */
2996  est = SCIPconvertRealToInt(scip, SCIPvarGetLbAtIndex(var, bdchgidx, FALSE));
2997  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(var, bdchgidx, FALSE));
2998 
2999  /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3000  * time window
3001  */
3002  if( est + duration > begin && lst < end )
3003  {
3004  overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3005 
3006  /* evaluated additionally local energy contribution */
3007  locenergies[v] = overlaps[v] * demand - glbenergy;
3008  assert(locenergies[v] >= 0);
3009  }
3010  }
3011 
3012  /* sort the variable contributions w.r.t. additional local energy contributions */
3013  SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3014 
3015  /* add local energy contributions until an overload is implied */
3016  for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3017  {
3018  SCIP_VAR* var;
3019  int duration;
3020  int overlap;
3021  int relaxlb;
3022  int relaxub;
3023  int idx;
3024 
3025  idx = idxs[v];
3026  assert(idx >= 0 && idx < nvars);
3027 
3028  var = vars[idx];
3029  assert(var != NULL);
3030  assert(var != infervar);
3031 
3032  duration = durations[idx];
3033  assert(duration > 0);
3034 
3035  overlap = overlaps[v];
3036  assert(overlap > 0);
3037 
3038  requiredenergy -= locenergies[v];
3039 
3040  if( requiredenergy < -1 )
3041  {
3042  int demand;
3043 
3044  demand = demands[idx];
3045  assert(demand > 0);
3046 
3047  overlap += (int)((requiredenergy + 1) / demand);
3048 
3049 #ifndef NDEBUG
3050  requiredenergy += locenergies[v];
3051  requiredenergy -= overlap * demand;
3052  assert(requiredenergy < 0);
3053 #endif
3054  }
3055  assert(overlap > 0);
3056 
3057  relaxlb = begin - duration + overlap;
3058  relaxub = end - overlap;
3059 
3060  SCIPdebugMessage("variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3061  SCIPvarGetName(var),
3064  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var),
3065  relaxlb, relaxub, demands[idx], duration);
3066 
3067  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3068  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3069 
3070  if( explanation != NULL )
3071  explanation[idx] = TRUE;
3072  }
3073 
3074  assert(requiredenergy < 0);
3075 
3076  SCIPfreeBufferArray(scip, &idxs);
3077  SCIPfreeBufferArray(scip, &overlaps);
3078  SCIPfreeBufferArray(scip, &locenergies);
3079 
3080  return SCIP_OKAY;
3081 }
3082 
3083 /** resolve propagation w.r.t. the cumulative condition */
3084 static
3086  SCIP* scip, /**< SCIP data structure */
3087  int nvars, /**< number of start time variables (activities) */
3088  SCIP_VAR** vars, /**< array of start time variables */
3089  int* durations, /**< array of durations */
3090  int* demands, /**< array of demands */
3091  int capacity, /**< cumulative capacity */
3092  int hmin, /**< left bound of time axis to be considered (including hmin) */
3093  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3094  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3095  INFERINFO inferinfo, /**< the user information */
3096  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3097  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3098  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3099  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3100  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3101  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3102  )
3103 {
3104  switch( inferInfoGetProprule(inferinfo) )
3105  {
3106  case PROPRULE_1_CORETIMES:
3107  {
3108  int inferdemand;
3109  int inferduration;
3110  int inferpos;
3111  int inferpeak;
3112  int relaxedpeak;
3113  int provedpeak;
3114 
3115  /* get the position of the inferred variable in the vars array */
3116  inferpos = inferInfoGetData1(inferinfo);
3117  if( inferpos >= nvars || vars[inferpos] != infervar )
3118  {
3119  /* find inference variable in constraint */
3120  for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3121  {}
3122  }
3123  assert(inferpos < nvars);
3124  assert(vars[inferpos] == infervar);
3125 
3126  inferdemand = demands[inferpos];
3127  inferduration = durations[inferpos];
3128 
3129  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3130  {
3131  /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3132  * the inference variable
3133  */
3134  assert(SCIPvarGetUbAtIndex(infervar, bdchgidx, FALSE) - SCIPvarGetUbAtIndex(infervar, bdchgidx, TRUE) < inferduration + 0.5);
3135 
3136  SCIPdebugMessage("variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3137  SCIPvarGetName(infervar), SCIPvarGetUbAtIndex(infervar, bdchgidx, FALSE),
3138  SCIPvarGetUbAtIndex(infervar, bdchgidx, TRUE), relaxedbd);
3139 
3140  /* get the inference peak that the time point which lead to the that propagtion */
3141  inferpeak = inferInfoGetData2(inferinfo);
3142  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3143  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3144  */
3145  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbAtIndex(infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3146  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) + inferduration;
3147 
3148  /* make sure that the relaxed peak is part of the effective horizon */
3149  relaxedpeak = MIN(relaxedpeak, hmax-1);
3150 
3151  /* make sure that relaxed peak is not larger than the infer peak
3152  *
3153  * This can happen in case the variable is not an active variable!
3154  */
3155  relaxedpeak = MAX(relaxedpeak, inferpeak);
3156  assert(relaxedpeak >= inferpeak);
3157  assert(relaxedpeak >= hmin);
3158  }
3159  else
3160  {
3161  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3162 
3163  SCIPdebugMessage("variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3164  SCIPvarGetName(infervar), SCIPvarGetLbAtIndex(infervar, bdchgidx, FALSE),
3165  SCIPvarGetLbAtIndex(infervar, bdchgidx, TRUE), relaxedbd);
3166 
3167  /* get the time interval where the job could not be scheduled */
3168  inferpeak = inferInfoGetData2(inferinfo);
3169  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3170  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3171  */
3172  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbAtIndex(infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3173  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) - 1;
3174 
3175  /* make sure that the relaxed peak is part of the effective horizon */
3176  relaxedpeak = MAX(relaxedpeak, hmin);
3177 
3178  /* make sure that relaxed peak is not larger than the infer peak
3179  *
3180  * This can happen in case the variable is not an active variable!
3181  */
3182  relaxedpeak = MIN(relaxedpeak, inferpeak);
3183  assert(relaxedpeak < hmax);
3184  }
3185 
3186  /* resolves the propagation of the core time algorithm */
3187  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3188  infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3189 
3190  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3191  {
3192  if( usebdwidening )
3193  {
3194  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3195  }
3196  else
3197  {
3198  /* old upper bound of variable itself is part of the explanation */
3199  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3200  }
3201  }
3202  else
3203  {
3204  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3205 
3206  if( usebdwidening )
3207  {
3208  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3209  }
3210  else
3211  {
3212  /* old lower bound of variable itself is part of the explanation */
3213  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3214  }
3215  }
3216 
3217  if( explanation != NULL )
3218  explanation[inferpos] = TRUE;
3219 
3220  break;
3221  }
3223  case PROPRULE_3_TTEF:
3224  {
3225  int begin;
3226  int end;
3227 
3228  begin = inferInfoGetData1(inferinfo);
3229  end = inferInfoGetData2(inferinfo);
3230  assert(begin < end);
3231 
3232  begin = MAX(begin, hmin);
3233  end = MIN(end, hmax);
3234 
3235  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3236  begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3237 
3238  break;
3239  }
3240 
3241  default:
3242  SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3243  SCIPABORT();
3244  return SCIP_INVALIDDATA; /*lint !e527*/
3245  }
3246 
3247  (*result) = SCIP_SUCCESS;
3248 
3249  return SCIP_OKAY;
3250 }
3251 
3252 /**@} */
3253 
3254 
3255 /**@name Enforcement methods
3256  *
3257  * @{
3258  */
3259 
3260 /** apply all fixings which are given by the alternative bounds */
3261 static
3263  SCIP* scip, /**< SCIP data structure */
3264  SCIP_VAR** vars, /**< array of active variables */
3265  int nvars, /**< number of active variables */
3266  int* alternativelbs, /**< alternative lower bounds */
3267  int* alternativeubs, /**< alternative lower bounds */
3268  int* downlocks, /**< number of constraints with down lock participating by the computation */
3269  int* uplocks, /**< number of constraints with up lock participating by the computation */
3270  SCIP_Bool* branched /**< pointer to store if a branching was applied */
3271  )
3272 {
3273  int v;
3274 
3275  for( v = 0; v < nvars; ++v )
3276  {
3277  SCIP_VAR* var;
3278  SCIP_Real objval;
3279 
3280  var = vars[v];
3281  assert(var != NULL);
3282 
3283  objval = SCIPvarGetObj(var);
3284 
3285  if( SCIPvarGetNLocksDown(var) == downlocks[v] && !SCIPisNegative(scip, objval) )
3286  {
3287  int ub;
3288 
3289  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3290 
3291  if( alternativelbs[v] <= ub )
3292  {
3293  SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3294  (*branched) = TRUE;
3295 
3296  SCIPdebugMessage("variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3297  SCIPvarGetLbLocal(var), alternativelbs[v]);
3298 
3299  return SCIP_OKAY;
3300  }
3301  }
3302 
3303  if( SCIPvarGetNLocksUp(var) == uplocks[v] && !SCIPisPositive(scip, objval) )
3304  {
3305  int lb;
3306 
3307  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3308 
3309  if( alternativeubs[v] >= lb )
3310  {
3311  SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3312  (*branched) = TRUE;
3313 
3314  SCIPdebugMessage("variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3315  alternativeubs[v], SCIPvarGetUbLocal(var));
3316 
3317  return SCIP_OKAY;
3318  }
3319  }
3320  }
3321 
3322  return SCIP_OKAY;
3323 }
3324 
3325 /** remove the capacity requirments for all job which start at the curtime */
3326 static
3328  SCIP_CONSDATA* consdata, /**< constraint data */
3329  int curtime, /**< current point in time */
3330  int* starttimes, /**< array of start times */
3331  int* startindices, /**< permutation with respect to the start times */
3332  int* freecapacity, /**< pointer to store the resulting free capacity */
3333  int* idx, /**< pointer to index in start time array */
3334  int nvars /**< number of vars in array of starttimes and startindices */
3335  )
3336 {
3337 
3338 #if defined SCIP_DEBUG && !defined NDEBUG
3339  int oldidx;
3340  oldidx = *idx;
3341 #endif
3342 
3343  assert(idx != NULL);
3344  assert(starttimes != NULL);
3345  assert(starttimes != NULL);
3346  assert(freecapacity != NULL);
3347  assert(starttimes[*idx] == curtime);
3348  assert(consdata->demands != NULL);
3349  assert(freecapacity != idx);
3350 
3351  /* subtract all capacity needed up to this point */
3352  (*freecapacity) -= consdata->demands[startindices[*idx]];
3353 
3354  while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3355  {
3356  ++(*idx);
3357  (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3358  assert(freecapacity != idx);
3359  }
3360 #ifdef SCIP_DEBUG
3361  assert(oldidx <= *idx);
3362 #endif
3363 }
3364 
3365 /** add the capacity requirments for all job which end at the curtime */
3366 static
3367 void addEndingJobDemands(
3368  SCIP_CONSDATA* consdata, /**< constraint data */
3369  int curtime, /**< current point in time */
3370  int* endtimes, /**< array of end times */
3371  int* endindices, /**< permutation with rspect to the end times */
3372  int* freecapacity, /**< pointer to store the resulting free capacity */
3373  int* idx, /**< pointer to index in end time array */
3374  int nvars /**< number of vars in array of starttimes and startindices */
3375  )
3376 {
3377 #if defined SCIP_DEBUG && !defined NDEBUG
3378  int oldidx;
3379  oldidx = *idx;
3380 #endif
3381 
3382  /* free all capacity usages of jobs the are no longer running */
3383  while( endtimes[*idx] <= curtime && *idx < nvars)
3384  {
3385  (*freecapacity) += consdata->demands[endindices[*idx]];
3386  ++(*idx);
3387  }
3388 
3389 #ifdef SCIP_DEBUG
3390  assert(oldidx <= *idx);
3391 #endif
3392 }
3393 
3394 /** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3395 static
3397  SCIP* scip, /**< SCIP data structure */
3398  SCIP_CONSDATA* consdata, /**< constraint handler data */
3399  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3400  int* timepoint /**< pointer to store the time point of the peak */
3401  )
3402 {
3403  int* starttimes; /* stores when each job is starting */
3404  int* endtimes; /* stores when each job ends */
3405  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3406  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3407 
3408  int nvars; /* number of activities for this constraint */
3409  int freecapacity; /* remaining capacity */
3410  int curtime; /* point in time which we are just checking */
3411  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3412 
3413  int hmin;
3414  int hmax;
3415 
3416  int j;
3417 
3418  assert(consdata != NULL);
3419 
3420  nvars = consdata->nvars;
3421  assert(nvars > 0);
3422 
3423  *timepoint = consdata->hmax;
3424 
3425  assert(consdata->vars != NULL);
3426 
3427  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3428  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3429  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3430  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3431 
3432  /* create event point arrays */
3433  createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3434  starttimes, endtimes, startindices, endindices);
3435 
3436  endindex = 0;
3437  freecapacity = consdata->capacity;
3438  hmin = consdata->hmin;
3439  hmax = consdata->hmax;
3440 
3441  /* check each startpoint of a job whether the capacity is kept or not */
3442  for( j = 0; j < nvars; ++j )
3443  {
3444  curtime = starttimes[j];
3445  SCIPdebugMessage("look at %d-th job with start %d\n", j, curtime);
3446 
3447  if( curtime >= hmax )
3448  break;
3449 
3450  /* remove the capacity requirments for all job which start at the curtime */
3451  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3452 
3453  /* add the capacity requirments for all job which end at the curtime */
3454  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3455 
3456  assert(freecapacity <= consdata->capacity);
3457  assert(endindex <= nvars);
3458 
3459  /* endindex - points to the next job which will finish */
3460  /* j - points to the last job that has been released */
3461 
3462  /* if free capacity is smaller than zero, then add branching candidates */
3463  if( freecapacity < 0 && curtime >= hmin )
3464  {
3465  *timepoint = curtime;
3466  break;
3467  }
3468  } /*lint --e{850}*/
3469 
3470  /* free all buffer arrays */
3471  SCIPfreeBufferArray(scip, &endindices);
3472  SCIPfreeBufferArray(scip, &startindices);
3473  SCIPfreeBufferArray(scip, &endtimes);
3474  SCIPfreeBufferArray(scip, &starttimes);
3475 
3476  return SCIP_OKAY;
3477 }
3478 
3479 /** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3480 static
3482  SCIP* scip, /**< SCIP data structure */
3483  SCIP_CONS** conss, /**< constraints to be processed */
3484  int nconss, /**< number of constraints */
3485  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3486  int* nbranchcands /**< pointer to store the number of branching variables */
3487  )
3488 {
3489  SCIP_HASHTABLE* collectedvars;
3490  int c;
3491 
3492  assert(scip != NULL);
3493  assert(conss != NULL);
3494 
3495  /* create a hash table */
3497  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3498 
3499  assert(scip != NULL);
3500  assert(conss != NULL);
3501 
3502  for( c = 0; c < nconss; ++c )
3503  {
3504  SCIP_CONS* cons;
3505  SCIP_CONSDATA* consdata;
3506 
3507  int curtime;
3508  int j;
3509 
3510  cons = conss[c];
3511  assert(cons != NULL);
3512 
3513  if( !SCIPconsIsActive(cons) )
3514  continue;
3515 
3516  consdata = SCIPconsGetData(cons);
3517  assert(consdata != NULL);
3518 
3519  /* get point in time when capacity is exceeded */
3520  SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3521 
3522  if( curtime < consdata->hmin || curtime >= consdata->hmax )
3523  continue;
3524 
3525  /* report all variables that are running at that point in time */
3526  for( j = 0; j < consdata->nvars; ++j )
3527  {
3528  SCIP_VAR* var;
3529  int lb;
3530  int ub;
3531 
3532  var = consdata->vars[j];
3533  assert(var != NULL);
3534 
3535  /* check if the variable was already added */
3536  if( SCIPhashtableExists(collectedvars, (void*)var) )
3537  continue;
3538 
3539  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3540  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3541 
3542  if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3543  {
3544  SCIP_Real solval;
3545  SCIP_Real score;
3546 
3547  solval = SCIPgetSolVal(scip, sol, var);
3548  score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3549 
3550  SCIPdebugMessage("add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3551  SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3552  (*nbranchcands)++;
3553 
3554  SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3555  }
3556  }
3557  }
3558 
3559  SCIPhashtableFree(&collectedvars);
3560 
3561  SCIPdebugMessage("found %d branching candidates\n", *nbranchcands);
3562 
3563  return SCIP_OKAY;
3564 }
3565 
3566 /** enforcement pseudo or LP solution */
3567 static
3569  SCIP* scip, /**< SCIP data structure */
3570  SCIP_CONS** conss, /**< constraints to be processed */
3571  int nconss, /**< number of constraints */
3572  SCIP_Bool branch, /**< should branching candidates be collected */
3573  SCIP_RESULT* result /**< pointer to store the result */
3574  )
3575 {
3576  if( branch )
3577  {
3578  int nbranchcands;
3579 
3580  nbranchcands = 0;
3581  SCIP_CALL( collectBranchingCands(scip, conss, nconss, NULL, &nbranchcands) );
3582 
3583  if( nbranchcands > 0 )
3584  (*result) = SCIP_INFEASIBLE;
3585  }
3586  else
3587  {
3588  SCIP_Bool violated;
3589  int c;
3590 
3591  violated = FALSE;
3592 
3593  /* first check if a constraints is violated */
3594  for( c = 0; c < nconss && !violated; ++c )
3595  {
3596  SCIP_CONS* cons;
3597 
3598  cons = conss[c];
3599  assert(cons != NULL);
3600 
3601  SCIP_CALL( checkCons(scip, cons, NULL, &violated, FALSE) );
3602  }
3603 
3604  if( violated )
3605  (*result) = SCIP_INFEASIBLE;
3606  }
3607 
3608  return SCIP_OKAY;
3609 }
3610 
3611 /**@} */
3612 
3613 /**@name Propagation
3614  *
3615  * @{
3616  */
3617 
3618 /** check if cumulative constraint is independently of all other constraints */
3619 static
3621  SCIP* scip, /**< SCIP data structure */
3622  SCIP_CONS* cons /**< cumulative constraint */
3623  )
3624 {
3625  SCIP_CONSDATA* consdata;
3626  SCIP_VAR** vars;
3627  SCIP_Bool* downlocks;
3628  SCIP_Bool* uplocks;
3629  int nvars;
3630  int v;
3631 
3632  consdata = SCIPconsGetData(cons);
3633  assert(consdata != NULL);
3634 
3635  nvars = consdata->nvars;
3636  vars = consdata->vars;
3637  downlocks = consdata->downlocks;
3638  uplocks = consdata->uplocks;
3639 
3640  /* check if the cumulative constraint has the only locks on the involved variables */
3641  for( v = 0; v < nvars; ++v )
3642  {
3643  SCIP_VAR* var;
3644 
3645  var = vars[v];
3646  assert(var != NULL);
3647 
3648  if( SCIPvarGetNLocksDown(var) > (int)downlocks[v] || SCIPvarGetNLocksUp(var) > (int)uplocks[v] )
3649  return FALSE;
3650  }
3651 
3652  return TRUE;
3653 }
3654 
3655 /** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3656  * (dual reductions)
3657  */
3658 static
3660  SCIP* scip, /**< SCIP data structure */
3661  SCIP_CONS* cons, /**< cumulative constraint */
3662  SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3663  int* nchgbds, /**< pointer to store the number changed variable bounds */
3664  int* nfixedvars, /**< pointer to count number of fixings */
3665  int* ndelconss, /**< pointer to count number of deleted constraints */
3666  SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3667  SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3668  )
3669 {
3670  SCIP_CONSDATA* consdata;
3671  SCIP_VAR** vars;
3672  SCIP_Real* objvals;
3673  SCIP_Real* lbs;
3674  SCIP_Real* ubs;
3675  SCIP_Real timelimit;
3676  SCIP_Real memorylimit;
3677  SCIP_Bool solved;
3678  SCIP_Bool error;
3679 
3680  int ncheckconss;
3681  int nvars;
3682  int v;
3683 
3684  assert(scip != NULL);
3685  assert(!SCIPconsIsModifiable(cons));
3686  assert(SCIPgetNConss(scip) > 0);
3687 
3688  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3689  * would/could end in an implication which can lead to cutoff of the/all optimal solution
3690  */
3691  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
3692  return SCIP_OKAY;
3693 
3694  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3695  * use the locks to decide for a dual reduction using this constraint;
3696  */
3697  if( !SCIPconsIsChecked(cons) )
3698  return SCIP_OKAY;
3699 
3700  ncheckconss = SCIPgetNCheckConss(scip);
3701 
3702  /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3703  * presolved problem do nothing execpt to change the parameter settings
3704  */
3705  if( ncheckconss == 1 )
3706  {
3707  /* shrink the minimal maximum value for the conflict length */
3708  SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3709 
3710  /* use only first unique implication point */
3711  SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3712 
3713  /* do not use reconversion conflicts */
3714  SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3715 
3716  /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3717  SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3718 
3719  /* increase the number of conflicts which induce a restart */
3720  SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3721 
3722  /* weight the variable which made into a conflict */
3723  SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3724 
3725  /* do not check pseudo solution (for performance reasons) */
3726  SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3727 
3728  /* use value based history to detect a reasonable branching point */
3729  SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3730 
3731  /* turn of LP relaxation */
3732  SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3733 
3734  /* prefer the down branch in case the value based history does not suggest something */
3735  SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3736 
3737  /* accept any bound change */
3738  SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3739 
3740  /* allow for at most 10 restart, after that the value based history should be reliable */
3741  SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3742 
3743  /* set priority for depth first search to highest possible value */
3744  SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3745 
3746  return SCIP_OKAY;
3747  }
3748 
3749  consdata = SCIPconsGetData(cons);
3750  assert(consdata != NULL);
3751 
3752  /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3753  * fail on the first place
3754  */
3755  if( consdata->triedsolving )
3756  return SCIP_OKAY;
3757 
3758  /* check if constraint is independently */
3759  if( !isConsIndependently(scip, cons) )
3760  return SCIP_OKAY;
3761 
3762  /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3763  * constraint is deleted; otherwise, we want to ensure that we do not try that again
3764  */
3765  consdata->triedsolving = TRUE;
3766 
3767  SCIPdebugMessage("the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3768  SCIPconsGetName(cons), SCIPgetNVars(scip), SCIPgetNConss(scip));
3769  SCIPdebugPrintCons(scip, cons, NULL);
3770 
3771  nvars = consdata->nvars;
3772  vars = consdata->vars;
3773 
3774  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3775  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3776  SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3777 
3778  for( v = 0; v < nvars; ++v )
3779  {
3780  SCIP_VAR* var;
3781 
3782  /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3783  * array
3784  */
3785  var = vars[v];
3786  assert(var != NULL);
3787 
3788  lbs[v] = SCIPvarGetLbLocal(var);
3789  ubs[v] = SCIPvarGetUbLocal(var);
3790 
3791  objvals[v] = SCIPvarGetObj(var);
3792  }
3793 
3794  /* check whether there is enough time and memory left */
3795  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3796  if( !SCIPisInfinity(scip, timelimit) )
3797  timelimit -= SCIPgetSolvingTime(scip);
3798  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3799 
3800  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3801  if( !SCIPisInfinity(scip, memorylimit) )
3802  {
3803  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3804  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3805  }
3806 
3807  /* solve the cumulative condition separately */
3808  SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3809  consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3810 
3811  if( !(*cutoff) && !(*unbounded) && !error )
3812  {
3813  SCIP_Bool infeasible;
3814  SCIP_Bool tightened;
3815  SCIP_Bool allfixed;
3816 
3817  allfixed = TRUE;
3818 
3819  for( v = 0; v < nvars; ++v )
3820  {
3821  /* check if variable is fixed */
3822  if( lbs[v] + 0.5 > ubs[v] )
3823  {
3824  SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3825  assert(!infeasible);
3826 
3827  if( tightened )
3828  {
3829  (*nfixedvars)++;
3830  consdata->triedsolving = FALSE;
3831  }
3832  }
3833  else
3834  {
3835  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3836  assert(!infeasible);
3837 
3838  if( tightened )
3839  {
3840  (*nchgbds)++;
3841  consdata->triedsolving = FALSE;
3842  }
3843 
3844  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3845  assert(!infeasible);
3846 
3847  if( tightened )
3848  {
3849  (*nchgbds)++;
3850  consdata->triedsolving = FALSE;
3851  }
3852 
3853  allfixed = FALSE;
3854  }
3855  }
3856 
3857  /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3858  if( allfixed )
3859  {
3860  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3861  (*ndelconss)++;
3862  }
3863  }
3864 
3865  SCIPfreeBufferArray(scip, &objvals);
3866  SCIPfreeBufferArray(scip, &ubs);
3867  SCIPfreeBufferArray(scip, &lbs);
3868 
3869  return SCIP_OKAY;
3870 }
3871 
3872 /** start conflict analysis to analysis the core insertion which is infeasible */
3873 static
3875  SCIP* scip, /**< SCIP data structure */
3876  int nvars, /**< number of start time variables (activities) */
3877  SCIP_VAR** vars, /**< array of start time variables */
3878  int* durations, /**< array of durations */
3879  int* demands, /**< array of demands */
3880  int capacity, /**< cumulative capacity */
3881  int hmin, /**< left bound of time axis to be considered (including hmin) */
3882  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3883  SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3884  int inferduration, /**< duration of the start time variable */
3885  int inferdemand, /**< demand of the start time variable */
3886  int inferpeak, /**< profile preak which causes the infeasibilty */
3887  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3888  SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3889  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3890  )
3891 {
3892  SCIPdebugMessage("detected infeasibility due to adding a core to the core resource profile\n");
3893  SCIPdebugMessage("variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3894  SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3895 
3896  /* initialize conflict analysis if conflict analysis is applicable */
3898  {
3900 
3901  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3902  infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3903 
3904  SCIPdebugMessage("add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3905 
3906  /* add both bound of the inference variable since these biuld the core which we could not inserted */
3907  if( usebdwidening )
3908  {
3909  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
3910  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
3911  }
3912  else
3913  {
3914  SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
3915  SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
3916  }
3917 
3918  *initialized = TRUE;
3919  }
3920 
3921  return SCIP_OKAY;
3922 }
3923 
3924 /** We are using the core resource profile which contains all core except the one of the start time variable which we
3925  * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
3926  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
3927  * analysis
3928  */
3929 static
3931  SCIP* scip, /**< SCIP data structure */
3932  int nvars, /**< number of start time variables (activities) */
3933  SCIP_VAR** vars, /**< array of start time variables */
3934  int* durations, /**< array of durations */
3935  int* demands, /**< array of demands */
3936  int capacity, /**< cumulative capacity */
3937  int hmin, /**< left bound of time axis to be considered (including hmin) */
3938  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3939  SCIP_CONS* cons, /**< constraint which is propagated */
3940  SCIP_PROFILE* profile, /**< resource profile */
3941  int idx, /**< position of the variable to propagate */
3942  int* nchgbds, /**< pointer to store the number of bound changes */
3943  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3944  SCIP_Bool* initialized, /**< was conflict analysis initialized */
3945  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3946  SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
3947  )
3948 {
3949  SCIP_VAR* var;
3950  int ntimepoints;
3951  int duration;
3952  int demand;
3953  int peak;
3954  int newlb;
3955  int est;
3956  int lst;
3957  int pos;
3958 
3959  var = vars[idx];
3960  assert(var != NULL);
3961 
3962  duration = durations[idx];
3963  assert(duration > 0);
3964 
3965  demand = demands[idx];
3966  assert(demand > 0);
3967 
3968  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3969  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3970  ntimepoints = SCIPprofileGetNTimepoints(profile);
3971 
3972  /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
3973  * load which we have at the earliest start time (lower bound)
3974  */
3975  (void) SCIPprofileFindLeft(profile, est, &pos);
3976 
3977  SCIPdebugMessage("propagate earliest start time (lower bound) (pos %d)\n", pos);
3978 
3979  /* we now trying to move the earliest start time in steps of at most "duration" length */
3980  do
3981  {
3982  INFERINFO inferinfo;
3983  SCIP_Bool tightened;
3984  int ect;
3985 
3986 #ifndef NDEBUG
3987  {
3988  /* in debug mode we check that we adjust the search position correctly */
3989  int tmppos;
3990 
3991  (void)SCIPprofileFindLeft(profile, est, &tmppos);
3992  assert(pos == tmppos);
3993  }
3994 #endif
3995  ect = est + duration;
3996  peak = -1;
3997 
3998  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
3999  * want a peak which is closest to the earliest completion time
4000  */
4001  do
4002  {
4003  /* check if the profile load conflicts with the demand of the start time variable */
4004  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4005  peak = pos;
4006 
4007  pos++;
4008  }
4009  while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4010 
4011  /* if we found no peak that means current the job could be scheduled at its earliest start time without
4012  * conflicting to the core resource profile
4013  */
4014  if( peak == -1 )
4015  break;
4016 
4017  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4018  * profile. That means we have to move it to the next time point in the resource profile but at most to the
4019  * earliest completion time (the remaining move will done in the next loop)
4020  */
4021  newlb = SCIPprofileGetTime(profile, peak+1);
4022  newlb = MIN(newlb, ect);
4023 
4024  /* if the earliest start time is greater than the lst we detected an infeasibilty */
4025  if( newlb > lst )
4026  {
4027  SCIPdebugMessage("variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4028 
4029  /* use conflict analysis to analysis the core insertion which was infeasible */
4030  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4031  var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4032 
4033  if( explanation != NULL )
4034  explanation[idx] = TRUE;
4035 
4036  *infeasible = TRUE;
4037 
4038  break;
4039  }
4040 
4041  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4042  * bound change
4043  */
4044  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4045 
4046  /* perform the bound lower bound change */
4047  SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4048  assert(tightened);
4049  assert(!(*infeasible));
4050 
4051  SCIPdebugMessage("variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4052  (*nchgbds)++;
4053 
4054  /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4056 
4057  /* adjust the earliest start time
4058  *
4059  * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4060  * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4061  * involved.
4062  */
4063  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4064  assert(est >= newlb);
4065 
4066  /* adjust the search position for the resource profile for the next step */
4067  if( est == SCIPprofileGetTime(profile, peak+1) )
4068  pos = peak + 1;
4069  else
4070  pos = peak;
4071  }
4072  while( est < lst );
4073 
4074  return SCIP_OKAY;
4075 }
4076 
4077 /** We are using the core resource profile which contains all core except the one of the start time variable which we
4078  * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4079  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4080  * analysis
4081  */
4082 static
4084  SCIP* scip, /**< SCIP data structure */
4085  SCIP_VAR* var, /**< start time variable to propagate */
4086  int duration, /**< duration of the job */
4087  int demand, /**< demand of the job */
4088  int capacity, /**< cumulative capacity */
4089  SCIP_CONS* cons, /**< constraint which is propagated */
4090  SCIP_PROFILE* profile, /**< resource profile */
4091  int idx, /**< position of the variable to propagate */
4092  int* nchgbds /**< pointer to store the number of bound changes */
4093  )
4094 {
4095  int ntimepoints;
4096  int newub;
4097  int peak;
4098  int pos;
4099  int est;
4100  int lst;
4101  int lct;
4102 
4103  assert(var != NULL);
4104  assert(duration > 0);
4105  assert(demand > 0);
4106 
4107  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4108  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4109 
4110  /* in case the start time variable is fixed do nothing */
4111  if( est == lst )
4112  return SCIP_OKAY;
4113 
4114  ntimepoints = SCIPprofileGetNTimepoints(profile);
4115 
4116  lct = lst + duration;
4117 
4118  /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4119  * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4120  * position gives us the load which we have at the latest completion time minus one
4121  */
4122  (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4123 
4124  SCIPdebugMessage("propagate upper bound (pos %d)\n", pos);
4125  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
4126 
4127  if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4128  return SCIP_OKAY;
4129 
4130  /* we now trying to move the latest start time in steps of at most "duration" length */
4131  do
4132  {
4133  INFERINFO inferinfo;
4134  SCIP_Bool tightened;
4135  SCIP_Bool infeasible;
4136 
4137  peak = -1;
4138 
4139 #ifndef NDEBUG
4140  {
4141  /* in debug mode we check that we adjust the search position correctly */
4142  int tmppos;
4143 
4144  (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4145  assert(pos == tmppos);
4146  }
4147 #endif
4148 
4149  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4150  * want a peak which is closest to the latest start time
4151  */
4152  do
4153  {
4154  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4155  peak = pos;
4156 
4157  pos--;
4158  }
4159  while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4160 
4161  /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4162  * to the core resource profile
4163  */
4164  if( peak == -1 )
4165  break;
4166 
4167  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4168  * profile. That means the job has be done until that point. Hence that gives us the latest completion
4169  * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4170  * doing in the next loop)
4171  */
4172  newub = SCIPprofileGetTime(profile, peak);
4173  newub = MAX(newub, lst) - duration;
4174  assert(newub >= est);
4175 
4176  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4177  * bound change
4178  */
4179  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4180 
4181  /* perform the bound upper bound change */
4182  SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4183  assert(tightened);
4184  assert(!infeasible);
4185 
4186  SCIPdebugMessage("variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4187  (*nchgbds)++;
4188 
4189  /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4191 
4192  /* adjust the latest start and completion time
4193  *
4194  * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4195  * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4196  * involved.
4197  */
4198  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4199  assert(lst <= newub);
4200  lct = lst + duration;
4201 
4202  /* adjust the search position for the resource profile for the next step */
4203  if( SCIPprofileGetTime(profile, peak) == lct )
4204  pos = peak - 1;
4205  else
4206  pos = peak;
4207  }
4208  while( est < lst );
4209 
4210  return SCIP_OKAY;
4211 }
4212 
4213 /** compute for the different earliest start and latest completion time the core energy of the corresponding time
4214  * points
4215  */
4216 static
4218  SCIP* scip, /**< SCIP data structure */
4219  SCIP_PROFILE* profile, /**< core profile */
4220  int nvars, /**< number of start time variables (activities) */
4221  int* ests, /**< array of sorted earliest start times */
4222  int* lcts, /**< array of sorted latest completion times */
4223  int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4224  int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4225  )
4226 {
4227  int ntimepoints;
4228  int energy;
4229  int t;
4230  int v;
4231 
4232  ntimepoints = SCIPprofileGetNTimepoints(profile);
4233  t = ntimepoints - 1;
4234  energy = 0;
4235 
4236  /* compute core energy after the earliest start time of each job */
4237  for( v = nvars-1; v >= 0; --v )
4238  {
4239  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4240  {
4241  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4242  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4243  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4244  t--;
4245  }
4246  assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4247 
4248  /* maybe ests[j] is in-between two timepoints */
4249  if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4250  {
4251  assert(t > 0);
4252  coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4253  }
4254  else
4255  coreEnergyAfterEst[v] = energy;
4256  }
4257 
4258  t = ntimepoints - 1;
4259  energy = 0;
4260 
4261  /* compute core energy after the latest completion time of each job */
4262  for( v = nvars-1; v >= 0; --v )
4263  {
4264  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4265  {
4266  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4267  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4268  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4269  t--;
4270  }
4271  assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4272 
4273  /* maybe lcts[j] is in-between two timepoints */
4274  if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4275  {
4276  assert(t > 0);
4277  coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4278  }
4279  else
4280  coreEnergyAfterLct[v] = energy;
4281  }
4282 
4283  return SCIP_OKAY;
4284 }
4285 
4286 /** collect earliest start times, latest completion time, and free energy contributions */
4287 static
4288 void collectDataTTEF(
4289  SCIP* scip, /**< SCIP data structure */
4290  int nvars, /**< number of start time variables (activities) */
4291  SCIP_VAR** vars, /**< array of start time variables */
4292  int* durations, /**< array of durations */
4293  int* demands, /**< array of demands */
4294  int hmin, /**< left bound of time axis to be considered (including hmin) */
4295  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4296  int* permests, /**< array to store the variable positions */
4297  int* ests, /**< array to store earliest start times */
4298  int* permlcts, /**< array to store the variable positions */
4299  int* lcts, /**< array to store latest completion times */
4300  int* ects, /**< array to store earliest completion times of the flexible part of the job */
4301  int* lsts, /**< array to store latest start times of the flexible part of the job */
4302  int* flexenergies /**< array to store the flexible energies of each job */
4303  )
4304 {
4305  int v;
4306 
4307  for( v = 0; v < nvars; ++ v)
4308  {
4309  int duration;
4310  int leftadjust;
4311  int rightadjust;
4312  int core;
4313  int est;
4314  int lct;
4315  int ect;
4316  int lst;
4317 
4318  duration = durations[v];
4319  assert(duration > 0);
4320 
4321  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4322  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
4323  ect = est + duration;
4324  lct = lst + duration;
4325 
4326  ests[v] = est;
4327  lcts[v] = lct;
4328  permests[v] = v;
4329  permlcts[v] = v;
4330 
4331  /* compute core time window which lies within the effective horizon */
4332  core = computeCoreWithInterval(hmin, hmax, ect, lst);
4333 
4334  /* compute the number of time steps the job could run before the effective horizon */
4335  leftadjust = MAX(0, hmin - est);
4336 
4337  /* compute the number of time steps the job could run after the effective horizon */
4338  rightadjust = MAX(0, lct - hmax);
4339 
4340  /* compute for each job the energy which is flexible; meaning not part of the core */
4341  flexenergies[v] = duration - leftadjust - rightadjust - core;
4342  flexenergies[v] = MAX(0, flexenergies[v]);
4343  flexenergies[v] *= demands[v];
4344  assert(flexenergies[v] >= 0);
4345 
4346  /* the earliest completion time of the flexible energy */
4347  ects[v] = MIN(ect, lst);
4348 
4349  /* the latest start time of the flexible energy */
4350  lsts[v] = MAX(ect, lst);
4351  }
4352 }
4353 
4354 /** try to tighten the lower bound of the given variable */
4355 static
4357  SCIP* scip, /**< SCIP data structure */
4358  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4359  int nvars, /**< number of start time variables (activities) */
4360  SCIP_VAR** vars, /**< array of start time variables */
4361  int* durations, /**< array of durations */
4362  int* demands, /**< array of demands */
4363  int capacity, /**< cumulative capacity */
4364  int hmin, /**< left bound of time axis to be considered (including hmin) */
4365  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4366  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4367  int duration, /**< duration of the job */
4368  int demand, /**< demand of the job */
4369  int est, /**< earliest start time of the job */
4370  int ect, /**< earliest completion time of the flexible part of the job */
4371  int lct, /**< latest completion time of the job */
4372  int begin, /**< begin of the time window under investigation */
4373  int end, /**< end of the time window under investigation */
4374  int energy, /**< available energy for the flexible part of the hob within the time window */
4375  int* bestlb, /**< pointer to strope the best lower bound change */
4376  int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4377  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4378  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4379  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4380  )
4381 {
4382  int newlb;
4383 
4384  assert(begin >= hmin);
4385  assert(end <= hmax);
4386 
4387  /* check if the time-table edge-finding should infer bounds */
4388  if( !conshdlrdata->ttefinfer )
4389  return SCIP_OKAY;
4390 
4391  /* if the job can be processed completely before or after the time window, nothing can be tightened */
4392  if( est >= end || ect <= begin )
4393  return SCIP_OKAY;
4394 
4395  /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4396  * skip since the overload check will do the job
4397  */
4398  if( est >= begin && ect <= end )
4399  return SCIP_OKAY;
4400 
4401  /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4402  * earliest start time
4403  */
4404  if( energy >= demand * (MAX(begin, est) - MIN(end, ect)) )
4405  return SCIP_OKAY;
4406 
4407  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4408  * present; therefore, we need to add the core;
4409  *
4410  * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4411  * compute the earliest completion time of the (whole) job
4412  */
4413  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4414 
4415  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4416  *
4417  * @note we can round down the compute duration w.r.t. the available energy
4418  */
4419  newlb = end - energy / demand;
4420 
4421  /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4422  * bound (latest start time); meaning it is not possible to schedule the job
4423  */
4424  if( newlb > lct - duration )
4425  {
4426  /* initialize conflict analysis if conflict analysis is applicable */
4428  {
4429  SCIP_Real relaxedbd;
4430 
4431  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4432 
4433  /* it is enough to overshoot the upper bound of the variable by one */
4434  relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4435 
4436  /* initialize conflict analysis */
4438 
4439  /* added to upper bound (which was overcut be new lower bound) of the variable */
4440  SCIP_CALL( SCIPaddConflictUb(scip, var, NULL) );
4441 
4442  /* analyze the infeasible */
4443  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4444  begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4445 
4446  (*initialized) = TRUE;
4447  }
4448 
4449  (*cutoff) = TRUE;
4450  }
4451  else if( newlb > (*bestlb) )
4452  {
4453  INFERINFO inferinfo;
4454 
4455  assert(newlb > begin);
4456 
4457  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4458 
4459  /* construct inference information */
4460  (*inferinfos) = inferInfoToInt(inferinfo);
4461  (*bestlb) = newlb;
4462  }
4463 
4464  return SCIP_OKAY;
4465 }
4466 
4467 /** try to tighten the upper bound of the given variable */
4468 static
4470  SCIP* scip, /**< SCIP data structure */
4471  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4472  int nvars, /**< number of start time variables (activities) */
4473  SCIP_VAR** vars, /**< array of start time variables */
4474  int* durations, /**< array of durations */
4475  int* demands, /**< array of demands */
4476  int capacity, /**< cumulative capacity */
4477  int hmin, /**< left bound of time axis to be considered (including hmin) */
4478  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4479  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4480  int duration, /**< duration of the job */
4481  int demand, /**< demand of the job */
4482  int est, /**< earliest start time of the job */
4483  int lst, /**< latest start time of the flexible part of the job */
4484  int lct, /**< latest completion time of the job */
4485  int begin, /**< begin of the time window under investigation */
4486  int end, /**< end of the time window under investigation */
4487  int energy, /**< available energy for the flexible part of the hob within the time window */
4488  int* bestub, /**< pointer to strope the best upper bound change */
4489  int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4490  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4491  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4492  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4493  )
4494 {
4495  int newub;
4496 
4497  assert(begin >= hmin);
4498  assert(end <= hmax);
4499  assert(est < begin);
4500 
4501  /* check if the time-table edge-finding should infer bounds */
4502  if( !conshdlrdata->ttefinfer )
4503  return SCIP_OKAY;
4504 
4505  /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4506  if( lst >= end || lct <= begin )
4507  return SCIP_OKAY;
4508 
4509  /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4510  * skip since the overload check will do the job
4511  */
4512  if( lst >= begin && lct <= end )
4513  return SCIP_OKAY;
4514 
4515  /* check if the available energy in the time window is to small to handle the flexible part of the job */
4516  if( energy >= demand * (MIN(end, lct) - MAX(begin, lst)) )
4517  return SCIP_OKAY;
4518 
4519  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4520  * present; therefore, we need to add the core;
4521  *
4522  * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4523  * latest start of the (whole) job
4524  */
4525  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4526  assert(energy >= 0);
4527 
4528  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4529  *
4530  * @note we can round down the compute duration w.r.t. the available energy
4531  */
4532  assert(demand > 0);
4533  newub = begin - duration + energy / demand;
4534 
4535  /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4536  * bound (earliest start time); meaning it is not possible to schedule the job
4537  */
4538  if( newub < est )
4539  {
4540  /* initialize conflict analysis if conflict analysis is applicable */
4542  {
4543  SCIP_Real relaxedbd;
4544 
4545  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4546 
4547  /* it is enough to undershoot the lower bound of the variable by one */
4548  relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4549 
4550  /* initialize conflict analysis */
4552 
4553  /* added to lower bound (which was undercut be new upper bound) of the variable */
4554  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
4555 
4556  /* analyze the infeasible */
4557  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4558  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4559 
4560  (*initialized) = TRUE;
4561  }
4562 
4563  (*cutoff) = TRUE;
4564  }
4565  else if( newub < (*bestub) )
4566  {
4567  INFERINFO inferinfo;
4568 
4569  assert(newub < begin);
4570 
4571  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4572 
4573  /* construct inference information */
4574  (*inferinfos) = inferInfoToInt(inferinfo);
4575  (*bestub) = newub;
4576  }
4577 
4578  return SCIP_OKAY;
4579 }
4580 
4581 /** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4582 static
4584  SCIP* scip, /**< SCIP data structure */
4585  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4586  int nvars, /**< number of start time variables (activities) */
4587  SCIP_VAR** vars, /**< array of start time variables */
4588  int* durations, /**< array of durations */
4589  int* demands, /**< array of demands */
4590  int capacity, /**< cumulative capacity */
4591  int hmin, /**< left bound of time axis to be considered (including hmin) */
4592  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4593  int* newlbs, /**< array to buffer new lower bounds */
4594  int* newubs, /**< array to buffer new upper bounds */
4595  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4596  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4597  int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4598  int* flexenergies, /**< array of flexible energies in the same order as the variables */
4599  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4600  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4601  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4602  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4603  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4604  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4605  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4606  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4607  )
4608 {
4609  int coreEnergyAfterEnd;
4610  int maxavailable;
4611  int minavailable;
4612  int totalenergy;
4613  int nests;
4614  int est;
4615  int lct;
4616  int start;
4617  int end;
4618  int v;
4619 
4620  est = INT_MAX;
4621  lct = INT_MIN;
4622 
4623  /* compute earliest start and latest completion time of all jobs */
4624  for( v = 0; v < nvars; ++v )
4625  {
4626  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4627  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4628 
4629  est = MIN(est, start);
4630  lct = MAX(lct, end);
4631  }
4632 
4633  /* adjust the effective time horizon */
4634  hmin = MAX(hmin, est);
4635  hmax = MIN(hmax, lct);
4636 
4637  end = hmax + 1;
4638  coreEnergyAfterEnd = -1;
4639 
4640  maxavailable = (hmax - hmin) * capacity;
4641  minavailable = maxavailable;
4642  totalenergy = computeTotalEnergy(durations, demands, nvars);
4643 
4644  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4645  if( (lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4646  return SCIP_OKAY;
4647 
4648  nests = nvars;
4649 
4650  /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4651  * times define the end of the time interval under investigation
4652  */
4653  for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4654  {
4655  int flexenergy;
4656  int minbegin;
4657  int lbenergy;
4658  int lbcand;
4659  int i;
4660 
4661  lct = lcts[v];
4662 
4663  /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4664  * infinity capacity is available; hence we skip that
4665  */
4666  if( lct > hmax )
4667  continue;
4668 
4669  /* if the latest completion time is smaller then hmin we have to stop */
4670  if( lct <= hmin )
4671  {
4672  assert(v == 0 || lcts[v-1] <= lcts[v]);
4673  break;
4674  }
4675 
4676  /* if the latest completion time equals to previous end time, we can continue since this particular interval
4677  * induced by end was just analyzed
4678  */
4679  if( lct == end )
4680  continue;
4681 
4682  assert(lct < end);
4683 
4684  /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4685  * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4686  * free energy; if so it means that in the next iterate the free-energy cannot be negative
4687  */
4688  if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4689  {
4690  int freeenergy;
4691 
4692  assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4693  assert(coreEnergyAfterEnd >= 0);
4694 
4695  /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4696  freeenergy = capacity * (end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4697 
4698  if( freeenergy <= minavailable )
4699  {
4700  SCIPdebugMessage("skip latest completion time <%d> (minimum available energy <%d>, free energy <%d>)\n", lct, minavailable, freeenergy);
4701  continue;
4702  }
4703  }
4704 
4705  SCIPdebugMessage("check intervals ending with <%d>\n", lct);
4706 
4707  end = lct;
4708  coreEnergyAfterEnd = coreEnergyAfterLct[v];
4709 
4710  flexenergy = 0;
4711  minavailable = maxavailable;
4712  minbegin = hmax;
4713  lbcand = -1;
4714  lbenergy = 0;
4715 
4716  /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4717  * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4718  * wider
4719  */
4720  for( i = nests-1; i >= 0; --i )
4721  {
4722  SCIP_VAR* var;
4723  int freeenergy;
4724  int duration;
4725  int demand;
4726  int begin;
4727  int idx;
4728  int lst;
4729 
4730  idx = perm[i];
4731  assert(idx >= 0);
4732  assert(idx < nvars);
4733  assert(!(*cutoff));
4734 
4735  /* the earliest start time of the job */
4736  est = ests[i];
4737 
4738  /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4739  * latest completion times (which define end) are scant in non-increasing order
4740  */
4741  if( end <= est )
4742  {
4743  nests--;
4744  continue;
4745  }
4746 
4747  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4748  * current ending time
4749  */
4750  if( (end - est) * capacity >= totalenergy )
4751  break;
4752 
4753  var = vars[idx];
4754  assert(var != NULL);
4755 
4756  duration = durations[idx];
4757  assert(duration > 0);
4758 
4759  demand = demands[idx];
4760  assert(demand > 0);
4761 
4762  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4763 
4764  /* the latest start time of the free part of the job */
4765  lst = lsts[idx];
4766 
4767  /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4768  * investigation; hence the overload check will do the the job
4769  */
4770  assert(est <= minbegin);
4771  if( minavailable < maxavailable && est < minbegin )
4772  {
4773  assert(!(*cutoff));
4774 
4775  /* try to tighten the upper bound */
4776  SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4777  var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4778  initialized, explanation, cutoff) );
4779 
4780  if( *cutoff )
4781  break;
4782  }
4783 
4784  SCIPdebugMessage("check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4785  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4786 
4787  begin = est;
4788  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4789 
4790  /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4791  * free energy
4792  */
4793  if( begin < hmin )
4794  break;
4795 
4796  /* compute the contribution to the flexible energy */
4797  if( lct <= end )
4798  {
4799  /* if the jobs has to finish before the end, all the energy has to be scheduled */
4800  assert(lst >= begin);
4801  assert(flexenergies[idx] >= 0);
4802  flexenergy += flexenergies[idx];
4803  }
4804  else
4805  {
4806  /* the job partly overlaps with the end */
4807  int candenergy;
4808  int energy;
4809 
4810  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4811  * w.r.t. latest start time
4812  *
4813  * @note we need to be aware of the effective horizon
4814  */
4815  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4816  assert(end - lst < duration);
4817  assert(energy >= 0);
4818 
4819  /* adjust the flexible energy of the time interval */
4820  flexenergy += energy;
4821 
4822  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4823  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4824  assert(candenergy >= 0);
4825 
4826  /* check if we found a better candidate */
4827  if( candenergy > lbenergy )
4828  {
4829  lbenergy = candenergy;
4830  lbcand = idx;
4831  }
4832  }
4833 
4834  SCIPdebugMessage("time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4835  assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4836 
4837  /* compute the energy which is not used yet */
4838  freeenergy = capacity * (end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4839 
4840  /* check overload */
4841  if( freeenergy < 0 )
4842  {
4843  SCIPdebugMessage("analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4844 
4845  /* initialize conflict analysis if conflict analysis is applicable */
4847  {
4848  /* analyze infeasibilty */
4850 
4851  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4852  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
4853  conshdlrdata->usebdwidening, explanation) );
4854 
4855  (*initialized) = TRUE;
4856  }
4857 
4858  (*cutoff) = TRUE;
4859 
4860  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4861  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
4862 
4863  break;
4864  }
4865 
4866  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4867  if( lbenergy > 0 && freeenergy < lbenergy )
4868  {
4869  int energy;
4870  int newlb;
4871  int ect;
4872 
4873  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4874  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4875 
4876  /* remove the energy of our job from the ... */
4877  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, end - lsts[lbcand])) * demands[lbcand];
4878 
4879  newlb = end - (int)(energy / demands[lbcand]);
4880 
4881  if( newlb > lst )
4882  {
4883  /* initialize conflict analysis if conflict analysis is applicable */
4885  {
4886  SCIP_Real relaxedbd;
4887 
4888  /* analyze infeasibilty */
4890 
4891  relaxedbd = lst + 1.0;
4892 
4893  /* added to upper bound (which was overcut be new lower bound) of the variable */
4894  SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4895 
4896  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4897  begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
4898  conshdlrdata->usebdwidening, explanation) );
4899 
4900  (*initialized) = TRUE;
4901  }
4902 
4903  (*cutoff) = TRUE;
4904  break;
4905  }
4906  else if( newlb > newlbs[lbcand] )
4907  {
4908  INFERINFO inferinfo;
4909 
4910  /* construct inference information */
4911  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4912 
4913  /* buffer upper bound change */
4914  lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
4915  newlbs[lbcand] = newlb;
4916  }
4917  }
4918 
4919  /* check if the current interval has a smaller free energy */
4920  if( minavailable > freeenergy )
4921  {
4922  minavailable = freeenergy;
4923  minbegin = begin;
4924  }
4925  assert(minavailable >= 0);
4926  }
4927  }
4928 
4929  return SCIP_OKAY;
4930 }
4931 
4932 /** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
4933 static
4935  SCIP* scip, /**< SCIP data structure */
4936  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4937  int nvars, /**< number of start time variables (activities) */
4938  SCIP_VAR** vars, /**< array of start time variables */
4939  int* durations, /**< array of durations */
4940  int* demands, /**< array of demands */
4941  int capacity, /**< cumulative capacity */
4942  int hmin, /**< left bound of time axis to be considered (including hmin) */
4943  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4944  int* newlbs, /**< array to buffer new lower bounds */
4945  int* newubs, /**< array to buffer new upper bounds */
4946  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4947  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4948  int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
4949  int* flexenergies, /**< array of flexible energies in the same order as the variables */
4950  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
4951  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4952  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4953  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4954  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4955  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4956  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4957  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4958  )
4959 {
4960  int coreEnergyAfterStart;
4961  int maxavailable;
4962  int minavailable;
4963  int totalenergy;
4964  int nlcts;
4965  int begin;
4966  int minest;
4967  int maxlct;
4968  int start;
4969  int end;
4970  int v;
4971 
4972  if( *cutoff )
4973  return SCIP_OKAY;
4974 
4975  begin = hmin - 1;
4976  coreEnergyAfterStart = -1;
4977 
4978  minest = INT_MAX;
4979  maxlct = INT_MIN;
4980 
4981  /* compute earliest start and latest completion time of all jobs */
4982  for( v = 0; v < nvars; ++v )
4983  {
4984  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4985  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4986 
4987  minest = MIN(minest, start);
4988  maxlct = MAX(maxlct, end);
4989  }
4990 
4991  /* adjust the effective time horizon */
4992  hmin = MAX(hmin, minest);
4993  hmax = MIN(hmax, maxlct);
4994 
4995  maxavailable = (hmax - hmin) * capacity;
4996  minavailable = maxavailable;
4997  totalenergy = computeTotalEnergy(durations, demands, nvars);
4998 
4999  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5000  if( (lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5001  return SCIP_OKAY;
5002 
5003  nlcts = 0;
5004 
5005  /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5006  * define the start of the time interval under investigation
5007  */
5008  for( v = 0; v < nvars; ++v )
5009  {
5010  int flexenergy;
5011  int minend;
5012  int ubenergy;
5013  int ubcand;
5014  int est;
5015  int i;
5016 
5017  est = ests[v];
5018 
5019  /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5020  * infinity capacity is available; hence we skip that
5021  */
5022  if( est < hmin )
5023  continue;
5024 
5025  /* if the earliest start time is larger or equal then hmax we have to stop */
5026  if( est >= hmax )
5027  break;
5028 
5029  /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5030  * induced by start was just analyzed
5031  */
5032  if( est == begin )
5033  continue;
5034 
5035  assert(est > begin);
5036 
5037  SCIPdebugMessage("check intervals starting with <%d>\n", est);
5038 
5039  begin = est;
5040  coreEnergyAfterStart = coreEnergyAfterEst[v];
5041 
5042  flexenergy = 0;
5043  minavailable = maxavailable;
5044  minend = hmin;
5045  ubcand = -1;
5046  ubenergy = 0;
5047 
5048  /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5049  * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5050  */
5051  for( i = nlcts; i < nvars; ++i )
5052  {
5053  SCIP_VAR* var;
5054  int freeenergy;
5055  int duration;
5056  int demand;
5057  int idx;
5058  int lct;
5059  int ect;
5060 
5061  idx = perm[i];
5062  assert(idx >= 0);
5063  assert(idx < nvars);
5064  assert(!(*cutoff));
5065 
5066  /* the earliest start time of the job */
5067  lct = lcts[i];
5068 
5069  /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5070  * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5071  */
5072  if( lct <= begin )
5073  {
5074  nlcts++;
5075  continue;
5076  }
5077 
5078  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5079  * start with current beginning time
5080  */
5081  if( (lct - begin) * capacity >= totalenergy )
5082  break;
5083 
5084  var = vars[idx];
5085  assert(var != NULL);
5086 
5087  duration = durations[idx];
5088  assert(duration > 0);
5089 
5090  demand = demands[idx];
5091  assert(demand > 0);
5092 
5093  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5094 
5095  /* the earliest completion time of the flexible part of the job */
5096  ect = ects[idx];
5097 
5098  /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5099  * investigation; hence the overload check will do the the job
5100  */
5101  assert(lct >= minend);
5102  if( minavailable < maxavailable && lct > minend )
5103  {
5104  assert(!(*cutoff));
5105 
5106  /* try to tighten the upper bound */
5107  SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5108  var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5109  initialized, explanation, cutoff) );
5110 
5111  if( *cutoff )
5112  return SCIP_OKAY;
5113  }
5114 
5115  SCIPdebugMessage("check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5116  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5117 
5118  end = lct;
5119  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5120 
5121  /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5122  * free energy
5123  */
5124  if( end > hmax )
5125  break;
5126 
5127  /* compute the contribution to the flexible energy */
5128  if( est >= begin )
5129  {
5130  /* if the jobs has to finish before the end, all the energy has to be scheduled */
5131  assert(ect <= end);
5132  assert(flexenergies[idx] >= 0);
5133  flexenergy += flexenergies[idx];
5134  }
5135  else
5136  {
5137  /* the job partly overlaps with the end */
5138  int candenergy;
5139  int energy;
5140 
5141  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5142  * w.r.t. latest start time
5143  *
5144  * @note we need to be aware of the effective horizon
5145  */
5146  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5147  assert(ect - begin < duration);
5148  assert(energy >= 0);
5149 
5150  /* adjust the flexible energy of the time interval */
5151  flexenergy += energy;
5152 
5153  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5154  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5155  assert(candenergy >= 0);
5156 
5157  /* check if we found a better candidate */
5158  if( candenergy > ubenergy )
5159  {
5160  ubenergy = candenergy;
5161  ubcand = idx;
5162  }
5163  }
5164 
5165  SCIPdebugMessage("time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5166  assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5167 
5168  /* compute the energy which is not used yet */
5169  freeenergy = capacity * (end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5170 
5171  /* check overload */
5172  if( freeenergy < 0 )
5173  {
5174  SCIPdebugMessage("analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5175 
5176  /* initialize conflict analysis if conflict analysis is applicable */
5178  {
5179  /* analyze infeasibilty */
5181 
5182  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5183  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
5184  conshdlrdata->usebdwidening, explanation) );
5185 
5186  (*initialized) = TRUE;
5187  }
5188 
5189  (*cutoff) = TRUE;
5190 
5191  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5192  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5193 
5194  return SCIP_OKAY;
5195  }
5196 
5197  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5198  if( ubenergy > 0 && freeenergy < ubenergy )
5199  {
5200  int energy;
5201  int newub;
5202  int lst;
5203 
5204  duration = durations[ubcand];
5205  assert(duration > 0);
5206 
5207  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5208  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5209 
5210  /* remove the energy of our job from the ... */
5211  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, ects[ubcand] - begin)) * demands[ubcand];
5212 
5213  newub = begin - duration + (int)(energy / demands[ubcand]);
5214 
5215  if( newub < ect - duration )
5216  {
5217  /* initialize conflict analysis if conflict analysis is applicable */
5219  {
5220  SCIP_Real relaxedbd;
5221  /* analyze infeasibilty */
5223 
5224  relaxedbd = ect - duration - 1.0;
5225 
5226  /* added to lower bound (which was undercut be new upper bound) of the variable */
5227  SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5228 
5229  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5230  begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5231  conshdlrdata->usebdwidening, explanation) );
5232 
5233  (*initialized) = TRUE;
5234  }
5235 
5236  (*cutoff) = TRUE;
5237  return SCIP_OKAY;
5238  }
5239  else if( newub < newubs[ubcand] )
5240  {
5241  INFERINFO inferinfo;
5242 
5243  /* construct inference information */
5244  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5245 
5246  /* buffer upper bound change */
5247  ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5248  newubs[ubcand] = newub;
5249  }
5250  }
5251 
5252  /* check if the current interval has a smaller free energy */
5253  if( minavailable > freeenergy )
5254  {
5255  minavailable = freeenergy;
5256  minend = end;
5257  }
5258  assert(minavailable >= 0);
5259  }
5260  }
5261 
5262  return SCIP_OKAY;
5263 }
5264 
5265 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5266  * edge-finding
5267  *
5268  * @note The algorithm is based on the following two papers:
5269  * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5270  * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5271  * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5272  * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5273  * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5274  */
5275 static
5277  SCIP* scip, /**< SCIP data structure */
5278  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5279  SCIP_PROFILE* profile, /**< current core profile */
5280  int nvars, /**< number of start time variables (activities) */
5281  SCIP_VAR** vars, /**< array of start time variables */
5282  int* durations, /**< array of durations */
5283  int* demands, /**< array of demands */
5284  int capacity, /**< cumulative capacity */
5285  int hmin, /**< left bound of time axis to be considered (including hmin) */
5286  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5287  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5288  int* nchgbds, /**< pointer to store the number of bound changes */
5289  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5290  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5291  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5292  )
5293 {
5294  int* coreEnergyAfterEst;
5295  int* coreEnergyAfterLct;
5296  int* flexenergies;
5297  int* permests;
5298  int* permlcts;
5299  int* lcts;
5300  int* ests;
5301  int* ects;
5302  int* lsts;
5303 
5304  int* newlbs;
5305  int* newubs;
5306  int* lbinferinfos;
5307  int* ubinferinfos;
5308 
5309  int v;
5310 
5311  /* check if a cutoff was already detected */
5312  if( (*cutoff) )
5313  return SCIP_OKAY;
5314 
5315  /* check if at least the basic overload checking should be perfomed */
5316  if( !conshdlrdata->ttefcheck )
5317  return SCIP_OKAY;
5318 
5319  SCIPdebugMessage("run time-table edge-finding overload checking\n");
5320 
5321  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5322  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5323  SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5324  SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5325  SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5326  SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5327  SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5328  SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5329  SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5330 
5331  SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5332  SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5333  SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5334  SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5335 
5336  /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5337  for( v = 0; v < nvars; ++v )
5338  {
5339  newlbs[v] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5340  newubs[v] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5341  lbinferinfos[v] = 0;
5342  ubinferinfos[v] = 0;
5343  }
5344 
5345  /* collect earliest start times, latest completion time, and free energy contributions */
5346  collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5347 
5348  /* sort the earliest start times and latest completion in non-decreasing order */
5349  SCIPsortIntInt(ests, permests, nvars);
5350  SCIPsortIntInt(lcts, permlcts, nvars);
5351 
5352  /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5353  * points
5354  */
5355  SCIP_CALL( computeCoreEngeryAfter(scip, profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct) );
5356 
5357  /* propagate the upper bounds and "opportunistically" the lower bounds */
5358  SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5359  newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5360  permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5361 
5362  /* propagate the lower bounds and "opportunistically" the upper bounds */
5363  SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5364  newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5365  permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5366 
5367  /* apply the buffer bound changes */
5368  for( v = 0; v < nvars && !(*cutoff); ++v )
5369  {
5370  SCIP_Bool infeasible;
5371  SCIP_Bool tightened;
5372 
5373  SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v], TRUE, &infeasible, &tightened) );
5374 
5375  /* since we change first the lower bound of the variable an infeasibilty should be detected */
5376  assert(!infeasible);
5377 
5378  if( tightened )
5379  {
5380  (*nchgbds)++;
5381 
5382  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5384  }
5385 
5386 
5387  SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v], TRUE, &infeasible, &tightened) );
5388 
5389  /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5390  * bound update can be infeasible
5391  */
5392  if( infeasible )
5393  {
5395  {
5396  INFERINFO inferinfo;
5397  SCIP_VAR* var;
5398  int begin;
5399  int end;
5400 
5401  var = vars[v];
5402  assert(var != NULL);
5403 
5404  /* initialize conflict analysis */
5406 
5407  /* convert int to inference information */
5408  inferinfo = intToInferInfo(ubinferinfos[v]);
5409 
5410  /* collect time window from inference information */
5411  begin = inferInfoGetData1(inferinfo);
5412  end = inferInfoGetData2(inferinfo);
5413  assert(begin < end);
5414 
5415  /* added to lower bound (which was undercut be new upper bound) of the variable */
5416  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
5417 
5418  /* analysis the upper bound change */
5419  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5420  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5421  conshdlrdata->usebdwidening, explanation) );
5422 
5423  (*initialized) = TRUE;
5424  }
5425 
5426  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5427  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5428 
5429  (*cutoff) = TRUE;
5430  break;
5431  }
5432 
5433  if( tightened )
5434  {
5435  (*nchgbds)++;
5436 
5437  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5439  }
5440  }
5441 
5442  SCIPfreeBufferArray(scip, &ubinferinfos);
5443  SCIPfreeBufferArray(scip, &lbinferinfos);
5444  SCIPfreeBufferArray(scip, &newubs);
5445  SCIPfreeBufferArray(scip, &newlbs);
5446 
5447  /* free buffer arrays */
5448  SCIPfreeBufferArray(scip, &lsts);
5449  SCIPfreeBufferArray(scip, &ects);
5450  SCIPfreeBufferArray(scip, &ests);
5451  SCIPfreeBufferArray(scip, &lcts);
5452  SCIPfreeBufferArray(scip, &permests);
5453  SCIPfreeBufferArray(scip, &permlcts);
5454  SCIPfreeBufferArray(scip, &flexenergies);
5455  SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5456  SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5457 
5458  return SCIP_OKAY;
5459 }
5460 
5461 /** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5462  * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5463  * time table propagator
5464  */
5465 static
5467  SCIP* scip, /**< SCIP data structure */
5468  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5469  SCIP_PROFILE* profile, /**< core profile */
5470  int nvars, /**< number of start time variables (activities) */
5471  SCIP_VAR** vars, /**< array of start time variables */
5472  int* durations, /**< array of durations */
5473  int* demands, /**< array of demands */
5474  int capacity, /**< cumulative capacity */
5475  int hmin, /**< left bound of time axis to be considered (including hmin) */
5476  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5477  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5478  int* nchgbds, /**< pointer to store the number of bound changes */
5479  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5480  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5481  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5482  )
5483 {
5484  SCIP_Bool infeasible;
5485  int v;
5486 
5487  assert(scip != NULL);
5488  assert(nvars > 0);
5489  assert(cons != NULL);
5490  assert(cutoff != NULL);
5491 
5492  /* check if already a cutoff was detected */
5493  if( (*cutoff) )
5494  return SCIP_OKAY;
5495 
5496  /* check if the time tabling should infer bounds */
5497  if( !conshdlrdata->ttinfer )
5498  return SCIP_OKAY;
5499 
5500  assert(*initialized == FALSE);
5501 
5502  SCIPdebugMessage("propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5503  SCIPconsGetName(cons), hmin, hmax, capacity);
5504 
5505  infeasible = FALSE;
5506 
5507  /* if core profile is empty; nothing to do */
5508  if( SCIPprofileGetNTimepoints(profile) <= 1 )
5509  return SCIP_OKAY;
5510 
5511  /* start checking each job whether the bounds can be improved */
5512  for( v = 0; v < nvars; ++v )
5513  {
5514  SCIP_VAR* var;
5515  int demand;
5516  int duration;
5517  int begin;
5518  int end;
5519  int est;
5520  int lst;
5521 
5522  var = vars[v];
5523  assert(var != NULL);
5524 
5525  duration = durations[v];
5526  assert(duration > 0);
5527 
5528  /* collect earliest and latest start time */
5529  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5530  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5531 
5532  /* check if the start time variables is already fixed; in that case we can ignore the job */
5533  if( est == lst )
5534  continue;
5535 
5536  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5537  if( lst + duration <= hmin || est >= hmax )
5538  continue;
5539 
5540  /* compute core interval w.r.t. effective time horizon */
5541  begin = MAX(hmin, lst);
5542  end = MIN(hmax, est + duration);
5543 
5544  demand = demands[v];
5545  assert(demand > 0);
5546 
5547  /* if the job has a core, remove it first */
5548  if( begin < end )
5549  {
5550  SCIPdebugMessage("variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5551  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5552 
5553  SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5554  }
5555 
5556  /* first try to update the earliest start time */
5557  SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5558  profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5559 
5560  if( *cutoff )
5561  break;
5562 
5563  /* second try to update the latest start time */
5564  SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5565  profile, v, nchgbds) );
5566 
5567  if( *cutoff )
5568  break;
5569 
5570  /* collect the potentially updated earliest and latest start time */
5571  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5572  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5573 
5574  /* compute core interval w.r.t. effective time horizon */
5575  begin = MAX(hmin, lst);
5576  end = MIN(hmax, est + duration);
5577 
5578  /* after updating the bound we might have a new core */
5579  if( begin < end )
5580  {
5581  int pos;
5582 
5583  SCIPdebugMessage("variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5584  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5585 
5586  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5587 
5588  if( infeasible )
5589  {
5590  /* use conflict analysis to analysis the core insertion which was infeasible */
5591  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5592  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5593 
5594  if( explanation != NULL )
5595  explanation[v] = TRUE;
5596 
5597  (*cutoff) = TRUE;
5598 
5599  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5600  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
5601 
5602  break;
5603  }
5604  }
5605  }
5606 
5607  return SCIP_OKAY;
5608 }
5609 
5610 
5611 /** node data structure for the binary tree used for edgefinding (with overload checking) */
5612 struct SCIP_NodeData
5613 {
5614  SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5615  SCIP_Real key; /**< key which is to insert the corresponding search node */
5616  int est; /**< earliest start time if the node data belongs to a leaf */
5617  int lct; /**< latest completion time if the node data belongs to a leaf */
5618  int demand; /**< demand of the job if the node data belongs to a leaf */
5619  int duration; /**< duration of the job if the node data belongs to a leaf */
5620  int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5621  int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5622  int enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5623  int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5624  int energylambda;
5625  int enveloplambda;
5626  int idx; /**< index of the start time variable in the (global) variable array */
5627  SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5628 };
5629 typedef struct SCIP_NodeData SCIP_NODEDATA;
5631 /** creates a node data structure */
5632 static
5634  SCIP* scip, /**< SCIP data structure */
5635  SCIP_NODEDATA** nodedata /**< pointer to store the create node data */
5636  )
5637 {
5638  SCIP_CALL( SCIPallocBuffer(scip, nodedata) );
5639  (*nodedata)->var = NULL;
5640  (*nodedata)->key = SCIP_INVALID;
5641  (*nodedata)->est = INT_MIN;
5642  (*nodedata)->lct = INT_MAX;
5643  (*nodedata)->duration = 0;
5644  (*nodedata)->demand = 0;
5645  (*nodedata)->enveloptheta = -1;
5646  (*nodedata)->energytheta = 0;
5647  (*nodedata)->enveloplambda = -1;
5648  (*nodedata)->energylambda = -1;
5649  (*nodedata)->idx = -1;
5650  (*nodedata)->intheta = TRUE;
5651 
5652  return SCIP_OKAY;
5653 }
5654 
5655 /** frees a node data structure */
5656 static
5657 void freeNodedata(
5658  SCIP* scip, /**< SCIP data structure */
5659  SCIP_NODEDATA** nodedata /**< pointer to store node data which should be freed */
5660  )
5661 {
5662  if( *nodedata != NULL )
5663  {
5664  SCIPfreeBuffer(scip, nodedata);
5665  }
5666 }
5667 
5668 /** update node data structure strating form the given node along the path to the root node */
5669 static
5671  SCIP* scip, /**< SCIP data structure */
5672  SCIP_BTNODE* node /**< search node which inserted */
5673  )
5674 {
5675  SCIP_BTNODE* left;
5676  SCIP_BTNODE* right;
5677  SCIP_NODEDATA* nodedata;
5678  SCIP_NODEDATA* leftdata;
5679  SCIP_NODEDATA* rightdata;
5680 
5681  SCIPdebugMessage("update envelop starting from node <%p>\n", (void*)node);
5682 
5683  if( SCIPbtnodeIsLeaf(node) )
5684  node = SCIPbtnodeGetParent(node);
5685 
5686  while( node != NULL )
5687  {
5688  /* get node data */
5689  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5690  assert(nodedata != NULL);
5691 
5692  /* collect node data from left node */
5693  left = SCIPbtnodeGetLeftchild(node);
5694  assert(left != NULL);
5695  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5696  assert(leftdata != NULL);
5697 
5698  /* collect node data from right node */
5699  right = SCIPbtnodeGetRightchild(node);
5700  assert(right != NULL);
5701  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5702  assert(rightdata != NULL);
5703 
5704  /* update envelop and energy */
5705  if( leftdata->enveloptheta >= 0 )
5706  {
5707  assert(rightdata->energytheta != -1);
5708  nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5709  }
5710  else
5711  nodedata->enveloptheta = rightdata->enveloptheta;
5712 
5713  assert(leftdata->energytheta != -1);
5714  assert(rightdata->energytheta != -1);
5715  nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5716 
5717  if( leftdata->enveloplambda >= 0 )
5718  {
5719  assert(rightdata->energytheta != -1);
5720  nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5721  }
5722  else
5723  nodedata->enveloplambda = rightdata->enveloplambda;
5724 
5725  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5726  nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5727 
5728  SCIPdebugMessage("node <%p> lambda envelop %d\n", (void*)node, nodedata->enveloplambda);
5729 
5730  if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5731  {
5732  assert(rightdata->energytheta != -1);
5733  assert(leftdata->energytheta != -1);
5734  nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5735  }
5736  else if( rightdata->energylambda >= 0 )
5737  {
5738  assert(leftdata->energytheta != -1);
5739  nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5740  }
5741  else if( leftdata->energylambda >= 0 )
5742  {
5743  assert(rightdata->energytheta != -1);
5744  nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5745  }
5746  else
5747  nodedata->energylambda = -1;
5748 
5749  /* go to parent */
5750  node = SCIPbtnodeGetParent(node);
5751  }
5752 
5753  SCIPdebugMessage("updating done\n");
5754 
5755  return SCIP_OKAY;
5756 }
5757 
5758 /** updates the key of the first parent on the trace which comes from left */
5759 static
5760 void updateKeyOnTrace(
5761  SCIP_BTNODE* node, /**< node to start the trace */
5762  SCIP_Real key /**< update search key */
5763  )
5764 {
5765  assert(node != NULL);
5766 
5767  while( !SCIPbtnodeIsRoot(node) )
5768  {
5769  SCIP_BTNODE* parent;
5770 
5771  parent = SCIPbtnodeGetParent(node);
5772  assert(parent != NULL);
5773 
5774  if( SCIPbtnodeIsLeftchild(node) )
5775  {
5776  SCIP_NODEDATA* nodedata;
5777 
5778  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(parent);
5779  assert(nodedata != NULL);
5780 
5781  nodedata->key = key;
5782  return;
5783  }
5784 
5785  node = parent;
5786  }
5787 }
5788 
5789 
5790 /** deletes the given node and updates all envelops */
5791 static
5793  SCIP* scip, /**< SCIP data structure */
5794  SCIP_BT* tree, /**< binary tree */
5795  SCIP_BTNODE* node /**< node to be deleted */
5796  )
5797 {
5798  SCIP_BTNODE* parent;
5799  SCIP_BTNODE* grandparent;
5800  SCIP_BTNODE* sibling;
5801 
5802  assert(scip != NULL);
5803  assert(tree != NULL);
5804  assert(node != NULL);
5805 
5806  assert(SCIPbtnodeIsLeaf(node));
5807  assert(!SCIPbtnodeIsRoot(node));
5808 
5809  SCIPdebugMessage("delete node <%p>\n", (void*)node);
5810 
5811  parent = SCIPbtnodeGetParent(node);
5812  assert(parent != NULL);
5813  if( SCIPbtnodeIsLeftchild(node) )
5814  {
5815  sibling = SCIPbtnodeGetRightchild(parent);
5816  SCIPbtnodeSetRightchild(parent, NULL);
5817  }
5818  else
5819  {
5820  sibling = SCIPbtnodeGetLeftchild(parent);
5821  SCIPbtnodeSetLeftchild(parent, NULL);
5822  }
5823  assert(sibling != NULL);
5824 
5825  grandparent = SCIPbtnodeGetParent(parent);
5826 
5827  if( grandparent != NULL )
5828  {
5829  /* reset parent of sibling */
5830  SCIPbtnodeSetParent(sibling, grandparent);
5831 
5832  /* reset child of grandparent to sibling */
5833  if( SCIPbtnodeIsLeftchild(parent) )
5834  {
5835  SCIPbtnodeSetLeftchild(grandparent, sibling);
5836  }
5837  else
5838  {
5839  SCIP_NODEDATA* nodedata;
5840 
5841  assert(SCIPbtnodeIsRightchild(parent));
5842  SCIPbtnodeSetRightchild(grandparent, sibling);
5843 
5844  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(sibling);
5845 
5846  updateKeyOnTrace(grandparent, nodedata->key);
5847  }
5848 
5849  SCIP_CALL( updateEnvelop(scip, grandparent) );
5850  }
5851  else
5852  {
5853  SCIPbtnodeSetParent(sibling, NULL);
5854 
5855  SCIPbtSetRoot(tree, sibling);
5856  }
5857 
5858 
5859  SCIPbtnodeFree(tree, &parent);
5860 
5861  return SCIP_OKAY;
5862 }
5863 
5864 /** moves a node form the theta set into the lambda set and updates the envelops */
5865 static
5867  SCIP* scip, /**< SCIP data structure */
5868  SCIP_BT* tree, /**< binary tree */
5869  SCIP_BTNODE* node /**< node to move into the lambda set */
5870  )
5871 {
5872  SCIP_NODEDATA* nodedata;
5873 
5874  assert(scip != NULL);
5875  assert(tree != NULL);
5876  assert(node != NULL);
5877 
5878  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5879  assert(nodedata != NULL);
5880  assert(nodedata->intheta);
5881 
5882  /* move the contributions form the theta set into the lambda set */
5883  assert(nodedata->enveloptheta != -1);
5884  assert(nodedata->energytheta != -1);
5885  assert(nodedata->enveloplambda == -1);
5886  assert(nodedata->energylambda == -1);
5887  nodedata->enveloplambda = nodedata->enveloptheta;
5888  nodedata->energylambda = nodedata->energytheta;
5889 
5890  nodedata->enveloptheta = -1;
5891  nodedata->energytheta = 0;
5892  nodedata->intheta = FALSE;
5893 
5894  /* update the energy and envelop values on trace */
5895  SCIP_CALL( updateEnvelop(scip, node) );
5896 
5897  return SCIP_OKAY;
5898 }
5899 
5900 /** inserts a node into the theta set and update the envelops */
5901 static
5903  SCIP* scip, /**< SCIP data structure */
5904  SCIP_BT* tree, /**< binary tree */
5905  SCIP_BTNODE* node, /**< node to insert */
5906  SCIP_NODEDATA** nodedatas, /**< array of node data */
5907  int* nnodedatas /**< pointer to number of node data */
5908  )
5909 {
5910  /* if the tree is empty the node will be the root node */
5911  if( SCIPbtIsEmpty(tree) )
5912  {
5913  SCIPbtSetRoot(tree, node);
5914  }
5915  else
5916  {
5917  SCIP_NODEDATA* newnodedata;
5918  SCIP_NODEDATA* leafdata;
5919  SCIP_NODEDATA* nodedata;
5920  SCIP_BTNODE* leaf;
5921  SCIP_BTNODE* newnode;
5922  SCIP_BTNODE* parent;
5923 
5924  leaf = SCIPbtGetRoot(tree);
5925  assert(leaf != NULL);
5926 
5927  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5928  assert(leafdata != NULL);
5929 
5930  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5931  assert(nodedata != NULL);
5932  assert(nodedata->intheta);
5933 
5934  /* find the position to insert the node */
5935  while( !SCIPbtnodeIsLeaf(leaf) )
5936  {
5937  if( nodedata->key < leafdata->key )
5938  leaf = SCIPbtnodeGetLeftchild(leaf);
5939  else
5940  leaf = SCIPbtnodeGetRightchild(leaf);
5941 
5942  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5943  assert(leafdata != NULL);
5944  }
5945 
5946  assert(leaf != NULL);
5947  assert(leaf != node);
5948 
5949  /* create node data */
5950  SCIP_CALL( createNodedata(scip, &newnodedata) );
5951 
5952  /* create a new node */
5953  SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
5954  assert(newnode != NULL);
5955 
5956  /* store node data to be able to delete them latter */
5957  nodedatas[*nnodedatas] = newnodedata;
5958  (*nnodedatas)++;
5959 
5960  parent = SCIPbtnodeGetParent(leaf);
5961 
5962  if( parent != NULL )
5963  {
5964  SCIPbtnodeSetParent(newnode, parent);
5965 
5966  /* check if the node is the left child */
5967  if( SCIPbtnodeGetLeftchild(parent) == leaf )
5968  {
5969  SCIPbtnodeSetLeftchild(parent, newnode);
5970  }
5971  else
5972  {
5973  SCIPbtnodeSetRightchild(parent, newnode);
5974  }
5975  }
5976  else
5977  SCIPbtSetRoot(tree, newnode);
5978 
5979  if( nodedata->key < leafdata->key )
5980  {
5981  /* node is on the left */
5982  SCIPbtnodeSetLeftchild(newnode, node);
5983  SCIPbtnodeSetRightchild(newnode, leaf);
5984  newnodedata->key = nodedata->key;
5985  }
5986  else
5987  {
5988  /* leaf is on the left */
5989  SCIPbtnodeSetLeftchild(newnode, leaf);
5990  SCIPbtnodeSetRightchild(newnode, node);
5991  newnodedata->key = leafdata->key;
5992  }
5993 
5994  SCIPbtnodeSetParent(leaf, newnode);
5995  SCIPbtnodeSetParent(node, newnode);
5996  }
5997 
5998  /* update envelop */
5999  SCIP_CALL( updateEnvelop(scip, node) );
6000 
6001  return SCIP_OKAY;
6002 }
6003 
6004 /** returns the leaf responsible for the lambda energy */
6005 static
6007  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6008  )
6009 {
6010  SCIP_BTNODE* left;
6011  SCIP_BTNODE* right;
6012  SCIP_NODEDATA* nodedata;
6013  SCIP_NODEDATA* leftdata;
6014  SCIP_NODEDATA* rightdata;
6015 
6016  assert(node != NULL);
6017 
6018  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6019  assert(nodedata != NULL);
6020 
6021  /* check if the node is the (responsible) leaf */
6022  if( SCIPbtnodeIsLeaf(node) )
6023  {
6024  assert(!nodedata->intheta);
6025  return node;
6026  }
6027 
6028  left = SCIPbtnodeGetLeftchild(node);
6029  assert(left != NULL);
6030 
6031  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6032  assert(leftdata != NULL);
6033 
6034  right = SCIPbtnodeGetRightchild(node);
6035  assert(right != NULL);
6036 
6037  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6038  assert(rightdata != NULL);
6039 
6040  assert(nodedata->energylambda != -1);
6041  assert(rightdata->energytheta != -1);
6042 
6043  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6045 
6046  assert(leftdata->energytheta != -1);
6047  assert(rightdata->energylambda != -1);
6048  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6049 
6051 }
6052 
6053 /** returns the leaf responsible for the lambda envelop */
6054 static
6056  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6057  )
6058 {
6059  SCIP_BTNODE* left;
6060  SCIP_BTNODE* right;
6061  SCIP_NODEDATA* nodedata;
6062  SCIP_NODEDATA* leftdata;
6063  SCIP_NODEDATA* rightdata;
6064 
6065  assert(node != NULL);
6066 
6067  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6068  assert(nodedata != NULL);
6069 
6070  /* check if the node is the (responsible) leaf */
6071  if( SCIPbtnodeIsLeaf(node) )
6072  {
6073  assert(!nodedata->intheta);
6074  return node;
6075  }
6076 
6077  left = SCIPbtnodeGetLeftchild(node);
6078  assert(left != NULL);
6079 
6080  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6081  assert(leftdata != NULL);
6082 
6083  right = SCIPbtnodeGetRightchild(node);
6084  assert(right != NULL);
6085 
6086  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6087  assert(rightdata != NULL);
6088 
6089  assert(nodedata->enveloplambda != -1);
6090  assert(rightdata->energytheta != -1);
6091 
6092  /* check if the left or right child is the one defining the envelop for the lambda set */
6093  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6095  else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6096  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6098 
6099  assert(rightdata->enveloplambda != -1);
6100  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6101 
6103 }
6104 
6105 
6106 /** reports all elements from set theta to generate a conflicting set */
6107 static
6108 void collectThetaSubtree(
6109  SCIP_BTNODE* node, /**< node within a theta subtree */
6110  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6111  int* nelements, /**< pointer to store the number of elements in omegaset */
6112  int* est, /**< pointer to store the earliest start time of the omega set */
6113  int* lct, /**< pointer to store the latest start time of the omega set */
6114  int* energy /**< pointer to store the energy of the omega set */
6115  )
6116 {
6117  SCIP_NODEDATA* nodedata;
6118 
6119  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6120  assert(nodedata != NULL);
6121 
6122  if( !SCIPbtnodeIsLeaf(node) )
6123  {
6124  collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6125  collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6126  }
6127  else if( nodedata->intheta )
6128  {
6129  assert(nodedata->var != NULL);
6130  SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6131 
6132  omegaset[*nelements] = node;
6133  (*est) = MIN(*est, nodedata->est);
6134  (*lct) = MAX(*lct, nodedata->lct);
6135  (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6136  (*nelements)++;
6137  }
6138 }
6139 
6140 
6141 /** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6142 static
6143 void traceThetaEnvelop(
6144  SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6145  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6146  int* nelements, /**< pointer to store the number of elements in omegaset */
6147  int* est, /**< pointer to store the earliest start time of the omega set */
6148  int* lct, /**< pointer to store the latest start time of the omega set */
6149  int* energy /**< pointer to store the energy of the omega set */
6150  )
6151 {
6152  assert(node != NULL);
6153 
6154  if( SCIPbtnodeIsLeaf(node) )
6155  {
6156  collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6157  }
6158  else
6159  {
6160  SCIP_BTNODE* left;
6161  SCIP_BTNODE* right;
6162  SCIP_NODEDATA* nodedata;
6163  SCIP_NODEDATA* leftdata;
6164  SCIP_NODEDATA* rightdata;
6165 
6166  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6167  assert(nodedata != NULL);
6168 
6169 
6170  left = SCIPbtnodeGetLeftchild(node);
6171  assert(left != NULL);
6172 
6173  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6174  assert(leftdata != NULL);
6175 
6176  right = SCIPbtnodeGetRightchild(node);
6177  assert(right != NULL);
6178 
6179  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6180  assert(rightdata != NULL);
6181 
6182  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6183  assert(nodedata != NULL);
6184 
6185  assert(nodedata->enveloptheta != -1);
6186  assert(rightdata->energytheta != -1);
6187 
6188  if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6189  {
6190  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6191  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6192  }
6193  else
6194  {
6195  assert(rightdata->enveloptheta != -1);
6196  assert(nodedata->enveloptheta == rightdata->enveloptheta);
6197  traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6198  }
6199  }
6200 }
6201 
6202 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6203 static
6204 void traceLambdaEnergy(
6205  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6206  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6207  int* nelements, /**< pointer to store the number of elements in omega set */
6208  int* est, /**< pointer to store the earliest start time of the omega set */
6209  int* lct, /**< pointer to store the latest start time of the omega set */
6210  int* energy /**< pointer to store the energy of the omega set */
6211  )
6212 {
6213  SCIP_BTNODE* left;
6214  SCIP_BTNODE* right;
6215  SCIP_NODEDATA* nodedata;
6216  SCIP_NODEDATA* leftdata;
6217  SCIP_NODEDATA* rightdata;
6218 
6219  assert(node != NULL);
6220 
6221  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6222  assert(nodedata != NULL);
6223 
6224  /* check if the node is a leaf */
6225  if( SCIPbtnodeIsLeaf(node) )
6226  return;
6227 
6228  left = SCIPbtnodeGetLeftchild(node);
6229  assert(left != NULL);
6230 
6231  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6232  assert(leftdata != NULL);
6233 
6234  right = SCIPbtnodeGetRightchild(node);
6235  assert(right != NULL);
6236 
6237  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6238  assert(rightdata != NULL);
6239 
6240  assert(nodedata->energylambda != -1);
6241  assert(rightdata->energytheta != -1);
6242 
6243  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6244  {
6245  traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6246  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6247  }
6248  else
6249  {
6250  assert(leftdata->energytheta != -1);
6251  assert(rightdata->energylambda != -1);
6252  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6253 
6254  collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6255  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6256  }
6257 }
6258 
6259 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6260 static
6261 void traceLambdaEnvelop(
6262  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6263  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6264  int* nelements, /**< pointer to store the number of elements in omega set */
6265  int* est, /**< pointer to store the earliest start time of the omega set */
6266  int* lct, /**< pointer to store the latest start time of the omega set */
6267  int* energy /**< pointer to store the energy of the omega set */
6268  )
6269 {
6270  SCIP_BTNODE* left;
6271  SCIP_BTNODE* right;
6272  SCIP_NODEDATA* nodedata;
6273  SCIP_NODEDATA* leftdata;
6274  SCIP_NODEDATA* rightdata;
6275 
6276  assert(node != NULL);
6277 
6278  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6279  assert(nodedata != NULL);
6280 
6281  /* check if the node is a leaf */
6282  if( SCIPbtnodeIsLeaf(node) )
6283  {
6284  assert(!nodedata->intheta);
6285  return;
6286  }
6287 
6288  left = SCIPbtnodeGetLeftchild(node);
6289  assert(left != NULL);
6290 
6291  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6292  assert(leftdata != NULL);
6293 
6294  right = SCIPbtnodeGetRightchild(node);
6295  assert(right != NULL);
6296 
6297  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6298  assert(rightdata != NULL);
6299 
6300  assert(nodedata->enveloplambda != -1);
6301  assert(rightdata->energytheta != -1);
6302 
6303  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6304  {
6305  traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6306  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6307  }
6308  else
6309  {
6310  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6311  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6312  {
6313  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6314  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6315  }
6316  else
6317  {
6318  assert(rightdata->enveloplambda != -1);
6319  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6320  traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6321  }
6322  }
6323 }
6324 
6325 /** compute the energy contribution by job which corresponds to the given leaf */
6326 static
6328  SCIP_BTNODE* node /**< leaf */
6329  )
6330 {
6331  SCIP_NODEDATA* nodedata;
6332  int duration;
6333 
6334  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6335  assert(nodedata != NULL);
6336  assert(nodedata->var != NULL);
6337 
6338  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6339  assert(duration > 0);
6340 
6341  SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6342  SCIPvarGetName(nodedata->var), SCIPvarGetLbLocal(nodedata->var), SCIPvarGetUbLocal(nodedata->var),
6343  SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6344 
6345  /* return energy which is contributed by the start time variable */
6346  return nodedata->demand * duration;
6347 }
6348 
6349 /** comparison method for two node data w.r.t. the earliest start time */
6350 static
6351 SCIP_DECL_SORTPTRCOMP(compNodeEst)
6353  int est1;
6354  int est2;
6355 
6356  est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6357  est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6358 
6359  return (est1 - est2);
6360 }
6361 
6362 /** comparison method for two node data w.r.t. the latest completion time */
6363 static
6364 SCIP_DECL_SORTPTRCOMP(compNodedataLct)
6366  int lct1;
6367  int lct2;
6368 
6369  lct1 = ((SCIP_NODEDATA*)elem1)->lct;
6370  lct2 = ((SCIP_NODEDATA*)elem2)->lct;
6371 
6372  return (lct1 - lct2);
6373 }
6374 
6375 
6376 /** an overload was detected; initialized conflict analysis, add an initial reason
6377  *
6378  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6379  */
6380 static
6382  SCIP* scip, /**< SCIP data structure */
6383  SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6384  int capacity, /**< cumulative capacity */
6385  int nleaves, /**< number of responsible leaves */
6386  int est, /**< earliest start time of the ...... */
6387  int lct, /**< latest completly time of the .... */
6388  int reportedenergy, /**< energy which already reported */
6389  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6390  int shift, /**< shift applied to all jobs before adding them to the tree */
6391  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6392  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6393  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6394  )
6395 {
6396  int energy;
6397  int j;
6398 
6399  /* do nothing if conflict analysis is not applicable */
6401  return SCIP_OKAY;
6402 
6403  SCIPdebugMessage("est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6404 
6405  /* compute energy of initial time window */
6406  energy = (lct - est) * capacity;
6407 
6408  /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6409  SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6410 
6411  /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6412  * thereby, compute the time window of interest
6413  */
6414  for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6415  {
6416  SCIP_NODEDATA* nodedata;
6417 
6418  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6419  assert(nodedata != NULL);
6420 
6421  reportedenergy += computeEnergyContribution(leaves[j]);
6422 
6423  /* adjust energy if the earliest start time decrease */
6424  if( nodedata->est < est )
6425  {
6426  est = nodedata->est;
6427  energy = (lct - est) * capacity;
6428  }
6429  }
6430  assert(reportedenergy > energy);
6431 
6432  SCIPdebugMessage("time window [%d,%d) available energy %d, required energy %d\n", est, lct, energy, reportedenergy);
6433 
6434  /* initialize conflict analysis */
6436 
6437  /* flip earliest start time and latest completion time */
6438  if( !propest )
6439  {
6440  SCIPswapInts(&est, &lct);
6441 
6442  /* shift earliest start time and latest completion time */
6443  lct = shift - lct;
6444  est = shift - est;
6445  }
6446  else
6447  {
6448  /* shift earliest start time and latest completion time */
6449  lct = lct + shift;
6450  est = est + shift;
6451  }
6452 
6453  nleaves = j;
6454 
6455  /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6456  * overloaded
6457  */
6458  for( j = nleaves-1; j >= 0; --j )
6459  {
6460  SCIP_NODEDATA* nodedata;
6461 
6462  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6463  assert(nodedata != NULL);
6464  assert(nodedata->var != NULL);
6465 
6466  /* check if bound widening should be used */
6467  if( usebdwidening )
6468  {
6469  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6470  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6471  }
6472  else
6473  {
6474  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6475  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6476  }
6477 
6478  if( explanation != NULL )
6479  explanation[nodedata->idx] = TRUE;
6480  }
6481 
6482  (*initialized) = TRUE;
6483 
6484  return SCIP_OKAY;
6485 }
6486 
6487 /** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6488  * responsible interval bounds in *est_omega and *lct_omega
6489  */
6490 static
6491 int computeEstOmegaset(
6492  SCIP* scip, /**< SCIP data structure */
6493  int duration, /**< duration of the job to move */
6494  int demand, /**< demand of the job to move */
6495  int capacity, /**< cumulative capacity */
6496  int est, /**< earliest start time of the omega set */
6497  int lct, /**< latest start time of the omega set */
6498  int energy /**< energy of the omega set */
6499  )
6500 {
6501  int newest;
6502 
6503  newest = 0;
6504 
6505  assert(scip != NULL);
6506 
6507  if( energy > (capacity - demand) * (lct - est) )
6508  {
6509  if( energy + demand * duration > capacity * (lct - est) )
6510  {
6511  newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6512  newest += est;
6513  }
6514  }
6515 
6516  return newest;
6517 }
6518 
6519 /** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6520  *
6521  * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6522  * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6523  */
6524 static
6526  SCIP* scip, /**< SCIP data structure */
6527  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6528  SCIP_CONS* cons, /**< constraint which is propagated */
6529  SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6530  SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6531  int capacity, /**< cumulative capacity */
6532  int ncands, /**< number of candidates */
6533  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6534  int shift, /**< shift applied to all jobs before adding them to the tree */
6535  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6536  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6537  int* nchgbds, /**< pointer to store the number of bound changes */
6538  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6539  )
6540 {
6541  SCIP_NODEDATA* rootdata;
6542  int j;
6543 
6544  assert(!SCIPbtIsEmpty(tree));
6545 
6546  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6547  assert(rootdata != NULL);
6548 
6549  /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6550  for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6551  {
6552  SCIP_NODEDATA* nodedata;
6553 
6554  if( SCIPbtnodeIsRoot(leaves[j]) )
6555  break;
6556 
6557  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6558  assert(nodedata->est != -1);
6559 
6560  /* check if the root lambda envelop exeeds the available capacity */
6561  while( !(*cutoff) && rootdata->enveloplambda > capacity * nodedata->lct )
6562  {
6563  SCIP_BTNODE** omegaset;
6564  SCIP_BTNODE* leaf;
6565  SCIP_NODEDATA* leafdata;
6566  int nelements;
6567  int energy;
6568  int newest;
6569  int est;
6570  int lct;
6571 
6572  assert(!(*cutoff));
6573 
6574  /* find responsible leaf for the lambda envelope */
6576  assert(leaf != NULL);
6577  assert(SCIPbtnodeIsLeaf(leaf));
6578 
6579  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6580  assert(leafdata != NULL);
6581  assert(!leafdata->intheta);
6582  assert(leafdata->duration > 0);
6583  assert(leafdata->est >= 0);
6584 
6585  /* check if the job has to be removed since its latest completion is to large */
6586  if( leafdata->est + leafdata->duration >= nodedata->lct )
6587  {
6588  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6589 
6590  /* the root might changed therefore we need to collect the new root node data */
6591  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6592  assert(rootdata != NULL);
6593 
6594  continue;
6595  }
6596 
6597  /* compute omega set */
6598  SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6599 
6600  nelements = 0;
6601  est = INT_MAX;
6602  lct = INT_MIN;
6603  energy = 0;
6604 
6605  /* collect the omega set from theta set */
6606  traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6607  assert(nelements > 0);
6608  assert(nelements < ncands);
6609 
6610  newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6611 
6612  /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6613  if( newest > lct )
6614  {
6615  SCIPdebugMessage("an overload was detected duration edge-finder propagattion\n");
6616 
6617  /* analyze over load */
6618  SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6619  conshdlrdata->usebdwidening, initialized, explanation) );
6620  (*cutoff) = TRUE;
6621 
6622  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6623  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6624  }
6625  else if( newest > 0 )
6626  {
6627  SCIP_Bool infeasible;
6628  SCIP_Bool tightened;
6629  INFERINFO inferinfo;
6630 
6631  if( propest )
6632  {
6633  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6634  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6635 
6636  SCIPdebugMessage("variable <%s> adjust lower bound from %g to %d\n",
6637  SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6638 
6639  SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6640  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6641 
6642  /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6644  }
6645  else
6646  {
6647  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6648  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6649 
6650  SCIPdebugMessage("variable <%s> adjust upper bound from %g to %d\n",
6651  SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6652 
6653  SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6654  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6655 
6656  /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6658  }
6659 
6660  /* adjust the earliest start time */
6661  if( tightened )
6662  {
6663  leafdata->est = newest;
6664  (*nchgbds)++;
6665  }
6666 
6667  if( infeasible )
6668  {
6669  /* initialize conflict analysis if conflict analysis is applicable */
6671  {
6672  int i;
6673 
6674  SCIPdebugMessage("edge-finder dectected an infeasibility\n");
6675 
6677 
6678  /* add lower and upper bound of variable which leads to the infeasibilty */
6679  SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6680  SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6681 
6682  if( explanation != NULL )
6683  explanation[leafdata->idx] = TRUE;
6684 
6685  /* add lower and upper bound of variable which lead to the infeasibilty */
6686  for( i = 0; i < nelements; ++i )
6687  {
6688  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6689  assert(nodedata != NULL);
6690 
6691  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6692  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6693 
6694  if( explanation != NULL )
6695  explanation[nodedata->idx] = TRUE;
6696  }
6697 
6698  (*initialized) = TRUE;
6699  }
6700 
6701  (*cutoff) = TRUE;
6702 
6703  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6704  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6705  }
6706  }
6707 
6708  /* free omegaset array */
6709  SCIPfreeBufferArray(scip, &omegaset);
6710 
6711  /* delete responsible leaf from lambda */
6712  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6713 
6714  /* the root might changed therefore we need to collect the new root node data */
6715  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6716  assert(rootdata != NULL);
6717  }
6718 
6719  /* move current job j from the theta set into the lambda set */
6720  SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6721  }
6722 
6723  return SCIP_OKAY;
6724 }
6725 
6726 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6727  *
6728  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6729  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6730  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6731  */
6732 static
6734  SCIP* scip, /**< SCIP data structure */
6735  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6736  int nvars, /**< number of start time variables (activities) */
6737  SCIP_VAR** vars, /**< array of start time variables */
6738  int* durations, /**< array of durations */
6739  int* demands, /**< array of demands */
6740  int capacity, /**< cumulative capacity */
6741  int hmin, /**< left bound of time axis to be considered (including hmin) */
6742  int hmax, /**< right bound of time axis to be considered (not including hmax) */
6743  SCIP_CONS* cons, /**< constraint which is propagated */
6744  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6745  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6746  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6747  int* nchgbds, /**< pointer to store the number of bound changes */
6748  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6749  )
6750 {
6751  SCIP_NODEDATA** nodedatas;
6752  SCIP_BTNODE** leaves;
6753  SCIP_BT* tree;
6754 
6755  int totalenergy;
6756  int nnodedatas;
6757  int ninsertcands;
6758  int ncands;
6759 
6760  int shift;
6761  int j;
6762 
6763  assert(scip != NULL);
6764  assert(cons != NULL);
6765  assert(initialized != NULL);
6766  assert(cutoff != NULL);
6767  assert(*cutoff == FALSE);
6768 
6769  SCIPdebugMessage("check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6770 
6771  SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6772  SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6773 
6774  ncands = 0;
6775  totalenergy = 0;
6776 
6777  SCIP_CALL( SCIPbtCreate(&tree, SCIPblkmem(scip)) );
6778 
6779  /* compute the shift which we apply to compute .... latest completion time of all jobs */
6780  if( propest )
6781  shift = 0;
6782  else
6783  {
6784  shift = 0;
6785 
6786  /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6787  * earliest start time propagation to handle the latest completion times
6788  */
6789  for( j = 0; j < nvars; ++j )
6790  {
6791  int lct;
6792 
6793  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6794  shift = MAX(shift, lct);
6795  }
6796  }
6797 
6798  /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6799  * horizon
6800  */
6801  for( j = 0; j < nvars; ++j )
6802  {
6803  SCIP_NODEDATA* nodedata;
6804  SCIP_VAR* var;
6805  int duration;
6806  int leftadjust;
6807  int rightadjust;
6808  int energy;
6809  int est;
6810  int lct;
6811 
6812  var = vars[j];
6813  assert(var != NULL);
6814 
6815  duration = durations[j];
6816  assert(duration > 0);
6817 
6818  leftadjust = 0;
6819  rightadjust = 0;
6820 
6821  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
6822  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6823 
6824  /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6825  * effective horizon [hmin,hmax)
6826  */
6827  if( conshdlrdata->useadjustedjobs )
6828  {
6829  if( est < hmin )
6830  {
6831  leftadjust = (hmin - est);
6832  est = hmin;
6833  }
6834  if( lct > hmax )
6835  {
6836  rightadjust = (lct - hmax);
6837  lct = hmax;
6838  }
6839 
6840  /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6841  * with the effective time horizon
6842  */
6843  if( duration - leftadjust - rightadjust <= 0 )
6844  continue;
6845  }
6846  else if( est < hmin || lct > hmax )
6847  continue;
6848 
6849  energy = demands[j] * (duration - leftadjust - rightadjust);
6850  assert(energy > 0);
6851 
6852  totalenergy += energy;
6853 
6854  /* flip earliest start time and latest completion time */
6855  if( !propest )
6856  {
6857  SCIPswapInts(&est, &lct);
6858 
6859  /* shift earliest start time and latest completion time */
6860  lct = shift - lct;
6861  est = shift - est;
6862  }
6863  else
6864  {
6865  /* shift earliest start time and latest completion time */
6866  lct = lct - shift;
6867  est = est - shift;
6868  }
6869  assert(est < lct);
6870  assert(est >= 0);
6871  assert(lct >= 0);
6872 
6873  /* create search node data */
6874  SCIP_CALL( createNodedata(scip, &nodedata) );
6875 
6876  /* initialize search node data */
6877  /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6878  nodedata->key = est + j / (2.0 * nvars);
6879  nodedata->var = var;
6880  nodedata->est = est;
6881  nodedata->lct = lct;
6882  nodedata->demand = demands[j];
6883  nodedata->duration = duration;
6884  nodedata->leftadjust = leftadjust;
6885  nodedata->rightadjust = rightadjust;
6886 
6887  /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6888  * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6889  * particular time interval [a,b] against the time interval [0,b].
6890  */
6891  nodedata->enveloptheta = capacity * est + energy;
6892  nodedata->energytheta = energy;
6893  nodedata->enveloplambda = -1;
6894  nodedata->energylambda = -1;
6895 
6896  nodedata->idx = j;
6897  nodedata->intheta = TRUE;
6898 
6899  nodedatas[ncands] = nodedata;
6900  ncands++;
6901  }
6902 
6903  nnodedatas = ncands;
6904 
6905  /* sort (non-decreasing) the jobs w.r.t. latest completion times */
6906  SCIPsortPtr((void**)nodedatas, compNodedataLct, ncands);
6907 
6908  ninsertcands = 0;
6909 
6910  /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
6911  * the root envelop detects an overload
6912  */
6913  for( j = 0; j < ncands; ++j )
6914  {
6915  SCIP_BTNODE* leaf;
6916  SCIP_NODEDATA* rootdata;
6917 
6918  /* check if the new job opens a time window which size is so large that it offers more energy than the total
6919  * energy of all candidate jobs. If so we skip that one.
6920  */
6921  if( (nodedatas[j]->lct - nodedatas[j]->est) * capacity >= totalenergy )
6922  {
6923  /* set the earliest start time to minus one to mark that candidate to be not used */
6924  nodedatas[j]->est = -1;
6925  continue;
6926  }
6927 
6928  /* create search node */
6929  SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)nodedatas[j]) );
6930 
6931  /* insert new node into the theta set and updete the envelops */
6932  SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, &nnodedatas) );
6933  assert(nnodedatas <= 2*nvars);
6934 
6935  /* move the inserted candidates together */
6936  leaves[ninsertcands] = leaf;
6937  ninsertcands++;
6938 
6939  assert(!SCIPbtIsEmpty(tree));
6940  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6941  assert(rootdata != NULL);
6942 
6943  /* check if the theta set envelops exceeds the available capacity */
6944  if( rootdata->enveloptheta > capacity * nodedatas[j]->lct )
6945  {
6946  SCIPdebugMessage("detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[j]->lct, j);
6947  (*cutoff) = TRUE;
6948 
6949  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6950  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverload++ );
6951 
6952  break;
6953  }
6954  }
6955 
6956  /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
6957  if( *cutoff )
6958  {
6959  int glbenery;
6960  int est;
6961  int lct;
6962 
6963  glbenery = 0;
6964  est = nodedatas[j]->est;
6965  lct = nodedatas[j]->lct;
6966 
6967  /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
6968  * which led to an overload
6969  */
6970  for( j = j+1; j < ncands; ++j )
6971  {
6972  SCIP_NODEDATA* nodedata;
6973  int duration;
6974  int glbest;
6975  int glblct;
6976 
6977  nodedata = nodedatas[j];
6978  assert(nodedata != NULL);
6979 
6980  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6981 
6982  /* get latest start time */
6983  glbest = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(nodedata->var));
6984  glblct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
6985 
6986  /* check if parts of the jobs run with the time window defined by the last inserted job */
6987  if( glbest < est )
6988  duration -= (est - glbest);
6989 
6990  if( glblct > lct )
6991  duration -= (glblct - lct);
6992 
6993  if( duration > 0 )
6994  {
6995  glbenery += nodedata->demand * duration;
6996 
6997  if( explanation != NULL )
6998  explanation[nodedata->idx] = TRUE;
6999  }
7000  }
7001 
7002  /* analyze the overload */
7003  SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7004  conshdlrdata->usebdwidening, initialized, explanation) );
7005  }
7006  else if( ninsertcands > 1 && conshdlrdata->efinfer )
7007  {
7008  /* if we have more than one job insterted and edge-finding should be performed we do it */
7009  SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7010  propest, shift, initialized, explanation, nchgbds, cutoff) );
7011  }
7012 
7013  /* free the search nodes data */
7014  for( j = nnodedatas - 1; j >= 0; --j )
7015  {
7016  freeNodedata(scip, &nodedatas[j]);
7017  }
7018 
7019  /* free theta tree */
7020  SCIPbtFree(&tree);
7021 
7022  /* free buffer arrays */
7023  SCIPfreeBufferArray(scip, &leaves);
7024  SCIPfreeBufferArray(scip, &nodedatas);
7025 
7026  return SCIP_OKAY;
7027 }
7028 
7029 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7030  *
7031  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7032  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7033  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7034  */
7035 static
7037  SCIP* scip, /**< SCIP data structure */
7038  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7039  int nvars, /**< number of start time variables (activities) */
7040  SCIP_VAR** vars, /**< array of start time variables */
7041  int* durations, /**< array of durations */
7042  int* demands, /**< array of demands */
7043  int capacity, /**< cumulative capacity */
7044  int hmin, /**< left bound of time axis to be considered (including hmin) */
7045  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7046  SCIP_CONS* cons, /**< constraint which is propagated */
7047  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7048  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7049  int* nchgbds, /**< pointer to store the number of bound changes */
7050  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7051  )
7052 {
7053  /* check if a cutoff was already detected */
7054  if( (*cutoff) )
7055  return SCIP_OKAY;
7056 
7057  /* check if at least the basic overload checking should be preformed */
7058  if( !conshdlrdata->efcheck )
7059  return SCIP_OKAY;
7060 
7061  /* check for overload, which may result in a cutoff */
7062  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7063  cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7064 
7065  /* check if a cutoff was detected */
7066  if( (*cutoff) )
7067  return SCIP_OKAY;
7068 
7069  /* check if bound should be infer */
7070  if( !conshdlrdata->efinfer )
7071  return SCIP_OKAY;
7072 
7073  /* check for overload, which may result in a cutoff */
7074  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7075  cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7076 
7077  return SCIP_OKAY;
7078 }
7079 
7080 /** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7081  * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7082  * event points
7083  */
7084 static
7086  SCIP* scip, /**< SCIP data structure */
7087  int nvars, /**< number of start time variables (activities) */
7088  SCIP_VAR** vars, /**< array of start time variables */
7089  int* durations, /**< array of durations */
7090  int* demands, /**< array of demands */
7091  int capacity, /**< cumulative capacity */
7092  int hmin, /**< left bound of time axis to be considered (including hmin) */
7093  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7094  SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7095  )
7096 {
7097 
7098  SCIP_VAR* var;
7099  int* starttimes; /* stores when each job is starting */
7100  int* endtimes; /* stores when each job ends */
7101  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7102  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7103 
7104  int lb;
7105  int ub;
7106  int freecapacity; /* remaining capacity */
7107  int curtime; /* point in time which we are just checking */
7108  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7109  int njobs;
7110  int j;
7111 
7112  assert(scip != NULL);
7113  assert(redundant != NULL);
7114 
7115  (*redundant) = TRUE;
7116 
7117  /* if no activities are associated with this cumulative then this constraint is redundant */
7118  if( nvars == 0 )
7119  return SCIP_OKAY;
7120 
7121  assert(vars != NULL);
7122 
7123  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7124  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7125  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7126  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7127 
7128  njobs = 0;
7129 
7130  /* assign variables, start and endpoints to arrays */
7131  for( j = 0; j < nvars; ++j )
7132  {
7133  assert(durations[j] > 0);
7134  assert(demands[j] > 0);
7135 
7136  var = vars[j];
7137  assert(var != NULL);
7138 
7139  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7140  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7141 
7142  /* check if jobs runs completely outside of the effective time horizon */
7143  if( lb >= hmax || ub + durations[j] <= hmin )
7144  continue;
7145 
7146  starttimes[njobs] = MAX(lb, hmin);
7147  startindices[njobs] = j;
7148 
7149  endtimes[njobs] = MIN(ub + durations[j], hmax);
7150  endindices[njobs] = j;
7151  assert(starttimes[njobs] <= endtimes[njobs]);
7152  njobs++;
7153  }
7154 
7155  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7156  SCIPsortIntInt(starttimes, startindices, njobs);
7157  SCIPsortIntInt(endtimes, endindices, njobs);
7158 
7159  endindex = 0;
7160  freecapacity = capacity;
7161 
7162  /* check each start point of a job whether the capacity is violated or not */
7163  for( j = 0; j < njobs; ++j )
7164  {
7165  curtime = starttimes[j];
7166 
7167  /* stop checking, if time point is above hmax */
7168  if( curtime >= hmax )
7169  break;
7170 
7171  /* subtract all capacity needed up to this point */
7172  freecapacity -= demands[startindices[j]];
7173  while( j+1 < njobs && starttimes[j+1] == curtime )
7174  {
7175  ++j;
7176  freecapacity -= demands[startindices[j]];
7177  }
7178 
7179  /* free all capacity usages of jobs the are no longer running */
7180  while( endtimes[endindex] <= curtime )
7181  {
7182  freecapacity += demands[endindices[endindex]];
7183  ++endindex;
7184  }
7185  assert(freecapacity <= capacity);
7186 
7187  /* check freecapacity to be smaller than zero */
7188  if( freecapacity < 0 && curtime >= hmin )
7189  {
7190  (*redundant) = FALSE;
7191  break;
7192  }
7193  } /*lint --e{850}*/
7194 
7195  /* free all buffer arrays */
7196  SCIPfreeBufferArray(scip, &endindices);
7197  SCIPfreeBufferArray(scip, &startindices);
7198  SCIPfreeBufferArray(scip, &endtimes);
7199  SCIPfreeBufferArray(scip, &starttimes);
7200 
7201  return SCIP_OKAY;
7202 }
7203 
7204 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7205  * completion time
7206  */
7207 static
7209  SCIP* scip, /**< SCIP data structure */
7210  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7211  SCIP_PROFILE* profile, /**< resource profile */
7212  int nvars, /**< number of variables (jobs) */
7213  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7214  int* durations, /**< array containing corresponding durations */
7215  int* demands, /**< array containing corresponding demands */
7216  int capacity, /**< cumulative capacity */
7217  int hmin, /**< left bound of time axis to be considered (including hmin) */
7218  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7219  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7220  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7221  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7222  )
7223 {
7224  int v;
7225 
7226  /* insert all cores */
7227  for( v = 0; v < nvars; ++v )
7228  {
7229  SCIP_VAR* var;
7230  SCIP_Bool infeasible;
7231  int duration;
7232  int demand;
7233  int begin;
7234  int end;
7235  int est;
7236  int lst;
7237  int pos;
7238 
7239  var = vars[v];
7240  assert(var != NULL);
7241  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(var)));
7242  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(var)));
7243 
7244  duration = durations[v];
7245  assert(duration > 0);
7246 
7247  demand = demands[v];
7248  assert(demand > 0);
7249 
7250  /* collect earliest and latest start time */
7251  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7252  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7253 
7254  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7255  if( lst + duration <= hmin || est >= hmax )
7256  continue;
7257 
7258  /* compute core interval w.r.t. effective time horizon */
7259  begin = MAX(hmin, lst);
7260  end = MIN(hmax, est + duration);
7261 
7262  /* check if a core exists */
7263  if( begin >= end )
7264  continue;
7265 
7266  SCIPdebugMessage("variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7267  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7268 
7269  /* insert the core into core resource profile (complexity O(log n)) */
7270  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7271 
7272  /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7273  if( infeasible )
7274  {
7275  assert(begin <= SCIPprofileGetTime(profile, pos));
7276  assert(end > SCIPprofileGetTime(profile, pos));
7277 
7278  /* use conflict analysis to analysis the core insertion which was infeasible */
7279  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7280  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7281 
7282  if( explanation != NULL )
7283  explanation[v] = TRUE;
7284 
7285  (*cutoff) = TRUE;
7286 
7287  /* for the statistic we count the number of times a cutoff was detected due the time-time */
7288  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
7289 
7290  break;
7291  }
7292  }
7293 
7294  return SCIP_OKAY;
7295 }
7296 
7297 /** propagate the cumulative condition */
7298 static
7300  SCIP* scip, /**< SCIP data structure */
7301  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7302  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7303  int nvars, /**< number of start time variables (activities) */
7304  SCIP_VAR** vars, /**< array of start time variables */
7305  int* durations, /**< array of durations */
7306  int* demands, /**< array of demands */
7307  int capacity, /**< cumulative capacity */
7308  int hmin, /**< left bound of time axis to be considered (including hmin) */
7309  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7310  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7311  int* nchgbds, /**< pointer to store the number of bound changes */
7312  SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7313  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7314  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7315  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7316  )
7317 {
7318  SCIP_PROFILE* profile;
7319 
7320  assert(nchgbds != NULL);
7321  assert(initialized != NULL);
7322  assert(cutoff != NULL);
7323  assert(!(*cutoff));
7324 
7325  /**@todo avoid always sorting the variable array */
7326 
7327  /* check if the constraint is redundant */
7328  SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7329 
7330  if( *redundant )
7331  return SCIP_OKAY;
7332 
7333  /* create an empty resource profile for profiling the cores of the jobs */
7334  SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7335 
7336  /* create core profile (compulsory parts) */
7337  SCIP_CALL( createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7338  initialized, explanation, cutoff) );
7339 
7340  /* propagate the job cores until nothing else can be detected */
7341  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7342  {
7343  SCIP_CALL( propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7344  nchgbds, initialized, explanation, cutoff) );
7345  }
7346 
7347  /* run edge finding propagator */
7348  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7349  {
7350  SCIP_CALL( propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7351  cons, initialized, explanation, nchgbds, cutoff) );
7352  }
7353 
7354  /* run time-table edge-finding propagator */
7355  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7356  {
7357  SCIP_CALL( propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7358  nchgbds, initialized, explanation, cutoff) );
7359  }
7360  /* free resource profile */
7361  SCIPprofileFree(&profile);
7362 
7363  return SCIP_OKAY;
7364 }
7365 
7366 /** propagate the cumulative constraint */
7367 static
7369  SCIP* scip, /**< SCIP data structure */
7370  SCIP_CONS* cons, /**< constraint to propagate */
7371  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7372  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7373  int* nchgbds, /**< pointer to store the number of bound changes */
7374  int* ndelconss, /**< pointer to store the number of deleted constraints */
7375  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7376  )
7377 {
7378  SCIP_CONSDATA* consdata;
7379  SCIP_Bool initialized;
7380  SCIP_Bool redundant;
7381  int oldnchgbds;
7382 
7383  assert(scip != NULL);
7384  assert(cons != NULL);
7385 
7386  consdata = SCIPconsGetData(cons);
7387  assert(consdata != NULL);
7388 
7389  oldnchgbds = *nchgbds;
7390  initialized = FALSE;
7391  redundant = FALSE;
7392 
7393  if( SCIPconsIsDeleted(cons) )
7394  {
7395  assert(SCIPinProbing(scip));
7396  return SCIP_OKAY;
7397  }
7398 
7399  /* if the constraint marked to be propagated, do nothing */
7400  if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7401  return SCIP_OKAY;
7402 
7403  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7404  consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7405  consdata->hmin, consdata->hmax, cons,
7406  nchgbds, &redundant, &initialized, NULL, cutoff) );
7407 
7408  if( redundant )
7409  {
7410  SCIPdebugMessage("%s deletes cumulative constraint <%s> since it is redundant\n",
7411  SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7412 
7413  if( !SCIPinProbing(scip) )
7414  {
7415  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7416  (*ndelconss)++;
7417  }
7418  }
7419  else
7420  {
7421  if( initialized )
7422  {
7423  /* run conflict analysis since it was initialized */
7424  assert(*cutoff == TRUE);
7425  SCIPdebugMessage("start conflict analysis\n");
7426  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7427  }
7428 
7429  /* if successful, reset age of constraint */
7430  if( *cutoff || *nchgbds > oldnchgbds )
7431  {
7432  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7433  }
7434  else
7435  {
7436  /* mark the constraint to be propagated */
7437  consdata->propagated = TRUE;
7438  }
7439  }
7440 
7441  return SCIP_OKAY;
7442 }
7443 
7444 /** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7445  * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7446  * be realize as domain reduction. Otherwise we do nothing
7447  */
7448 static
7450  SCIP* scip, /**< SCIP data structure */
7451  SCIP_VAR** vars, /**< problem variables */
7452  int nvars, /**< number of problem variables */
7453  int probingpos, /**< variable number to apply probing on */
7454  SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7455  SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7456  SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7457  SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7458  SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7459  SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7460  SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7461  SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7462  SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7463  SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7464  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7465  SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7466  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7467  )
7468 {
7469  SCIP_VAR* var;
7470  SCIP_Bool tightened;
7471 
7472  assert(probingpos >= 0);
7473  assert(probingpos < nvars);
7474  assert(success != NULL);
7475  assert(cutoff != NULL);
7476 
7477  var = vars[probingpos];
7478  assert(var != NULL);
7479  assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7480  assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7481  assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7482  assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7483 
7484  (*success) = FALSE;
7485 
7486  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7487  return SCIP_OKAY;
7488 
7489  /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7490  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7491  leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7492 
7493  if( (*cutoff) )
7494  {
7495  /* note that cutoff may occur if presolving has not been executed fully */
7496  SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7497 
7498  if( tightened )
7499  {
7500  (*success) =TRUE;
7501  (*nfixedvars)++;
7502  }
7503 
7504  return SCIP_OKAY;
7505  }
7506 
7507  /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7508  * presolving has not been executed fully
7509  */
7510  if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7511  {
7512  /* note that cutoff may occur if presolving has not been executed fully */
7513  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7514 
7515  if( tightened )
7516  {
7517  (*success) = TRUE;
7518  (*nfixedvars)++;
7519  }
7520 
7521  return SCIP_OKAY;
7522  }
7523 
7524  /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7525  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7526  rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7527 
7528  if( (*cutoff) )
7529  {
7530  /* note that cutoff may occur if presolving has not been executed fully */
7531  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7532 
7533  if( tightened )
7534  {
7535  (*success) =TRUE;
7536  (*nfixedvars)++;
7537  }
7538 
7539  return SCIP_OKAY;
7540  }
7541 
7542  return SCIP_OKAY;
7543 }
7544 
7545 /** is it possible, to round variable down w.r.t. objective function */
7546 static
7548  SCIP* scip, /**< SCIP data structure */
7549  SCIP_VAR* var, /**< problem variable */
7550  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7551  )
7552 {
7553  SCIP_Real objval;
7554  int scalar;
7555 
7556  assert(roundable != NULL);
7557 
7558  *roundable = TRUE;
7559 
7560  /* a fixed variable can be definition always be safely rounded */
7562  return SCIP_OKAY;
7563 
7564  /* in case the variable is not active we need to check the object coefficient of the active variable */
7565  if( !SCIPvarIsActive(var) )
7566  {
7567  SCIP_VAR* actvar;
7568  int constant;
7569 
7570  actvar = var;
7571 
7572  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7573  assert(scalar != 0);
7574 
7575  objval = scalar * SCIPvarGetObj(actvar);
7576  }
7577  else
7578  {
7579  scalar = 1;
7580  objval = SCIPvarGetObj(var);
7581  }
7582 
7583  /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7584  * (the transformed problem is always a minimization problem)
7585  *
7586  * @note that we need to check this condition w.r.t. active variable space
7587  */
7588  if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7589  *roundable = FALSE;
7590 
7591  return SCIP_OKAY;
7592 }
7593 
7594 /** is it possible, to round variable up w.r.t. objective function */
7595 static
7597  SCIP* scip, /**< SCIP data structure */
7598  SCIP_VAR* var, /**< problem variable */
7599  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7600  )
7601 {
7602  SCIP_Real objval;
7603  int scalar;
7604 
7605  assert(roundable != NULL);
7606 
7607  *roundable = TRUE;
7608 
7609  /* a fixed variable can be definition always be safely rounded */
7611  return SCIP_OKAY;
7612 
7613  /* in case the variable is not active we need to check the object coefficient of the active variable */
7614  if( !SCIPvarIsActive(var) )
7615  {
7616  SCIP_VAR* actvar;
7617  int constant;
7618 
7619  actvar = var;
7620 
7621  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7622  assert(scalar != 0);
7623 
7624  objval = scalar * SCIPvarGetObj(actvar);
7625  }
7626  else
7627  {
7628  scalar = 1;
7629  objval = SCIPvarGetObj(var);
7630  }
7631 
7632  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7633  * (the transformed problem is always a minimization problem)
7634  *
7635  * @note that we need to check this condition w.r.t. active variable space
7636  */
7637  if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7638  *roundable = FALSE;
7639 
7640  return SCIP_OKAY;
7641 }
7642 
7643 /** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7644  * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7645  * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7646  * the only one locking this variable in the corresponding direction.
7647  */
7648 static
7650  SCIP* scip, /**< SCIP data structure */
7651  SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7652  int nconss, /**< number of cumulative constraints */
7653  SCIP_Bool local, /**< use local bounds effective horizon? */
7654  int* alternativelbs, /**< alternative lower bounds */
7655  int* alternativeubs, /**< alternative lower bounds */
7656  int* downlocks, /**< number of constraints with down lock participating by the computation */
7657  int* uplocks /**< number of constraints with up lock participating by the computation */
7658  )
7659 {
7660  int nvars;
7661  int c;
7662  int v;
7663 
7664  for( c = 0; c < nconss; ++c )
7665  {
7666  SCIP_CONSDATA* consdata;
7667  SCIP_CONS* cons;
7668  SCIP_VAR* var;
7669  int hmin;
7670  int hmax;
7671 
7672  cons = conss[c];
7673  assert(cons != NULL);
7674 
7675  /* ignore constraints which are already deletet and those which are not check constraints */
7676  if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7677  continue;
7678 
7679  consdata = SCIPconsGetData(cons);
7680  assert(consdata != NULL);
7681  assert(consdata->nvars > 1);
7682 
7683  /* compute the hmin and hmax */
7684  if( local )
7685  {
7686  SCIP_PROFILE* profile;
7687 
7688  /* create empty resource profile with infinity resource capacity */
7689  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7690 
7691  /* create worst case resource profile */
7692  SCIP_CALL( SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands) );
7693 
7694  hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7695  hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7696 
7697  /* free worst case profile */
7698  SCIPprofileFree(&profile);
7699  }
7700  else
7701  {
7702  hmin = consdata->hmin;
7703  hmax = consdata->hmax;
7704  }
7705 
7706  consdata = SCIPconsGetData(cons);
7707  assert(consdata != NULL);
7708 
7709  nvars = consdata->nvars;
7710 
7711  for( v = 0; v < nvars; ++v )
7712  {
7713  int scalar;
7714  int constant;
7715  int idx;
7716 
7717  var = consdata->vars[v];
7718  assert(var != NULL);
7719 
7720  /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7721  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR);
7722 
7723  /* ignore variable locally fixed variables */
7724  if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7725  continue;
7726 
7727 
7728  SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7729  idx = SCIPvarGetProbindex(var);
7730  assert(idx >= 0);
7731 
7732  /* first check lower bound fixing */
7733  if( consdata->downlocks[v] )
7734  {
7735  int ect;
7736  int est;
7737 
7738  /* the variable has a down locked */
7739  est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7740  ect = est + consdata->durations[v];
7741 
7742  if( ect <= hmin || hmin >= hmax )
7743  downlocks[idx]++;
7744  else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7745  {
7746  alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7747  downlocks[idx]++;
7748  }
7749  }
7750 
7751  /* second check upper bound fixing */
7752  if( consdata->uplocks[v] )
7753  {
7754  int duration;
7755  int lct;
7756  int lst;
7757 
7758  duration = consdata->durations[v];
7759 
7760  /* the variable has a up lock locked */
7761  lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7762  lct = lst + duration;
7763 
7764  if( lst >= hmax || hmin >= hmax )
7765  uplocks[idx]++;
7766  else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7767  {
7768  alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7769  uplocks[idx]++;
7770  }
7771  }
7772  }
7773  }
7774 
7775  return SCIP_OKAY;
7776 }
7777 
7778 /** apply all fixings which are given by the alternative bounds */
7779 static
7781  SCIP* scip, /**< SCIP data structure */
7782  SCIP_VAR** vars, /**< array of active variables */
7783  int nvars, /**< number of active variables */
7784  int* alternativelbs, /**< alternative lower bounds */
7785  int* alternativeubs, /**< alternative lower bounds */
7786  int* downlocks, /**< number of constraints with down lock participating by the computation */
7787  int* uplocks, /**< number of constraints with up lock participating by the computation */
7788  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7789  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7790  )
7791 {
7792  SCIP_Real* downimpllbs;
7793  SCIP_Real* downimplubs;
7794  SCIP_Real* downproplbs;
7795  SCIP_Real* downpropubs;
7796  SCIP_Real* upimpllbs;
7797  SCIP_Real* upimplubs;
7798  SCIP_Real* upproplbs;
7799  SCIP_Real* uppropubs;
7800  int v;
7801 
7802  /* get temporary memory for storing probing results */
7803  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7804  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7805  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7806  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7807  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7808  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7809  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7810  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7811 
7812  for( v = 0; v < nvars; ++v )
7813  {
7814  SCIP_VAR* var;
7815  SCIP_Bool infeasible;
7816  SCIP_Bool fixed;
7817  SCIP_Bool roundable;
7818  int ub;
7819  int lb;
7820 
7821  var = vars[v];
7822  assert(var != NULL);
7823 
7824  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7825  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7826 
7827  /* ignore fixed variables */
7828  if( ub - lb <= 0 )
7829  continue;
7830 
7831 
7832  if( SCIPvarGetNLocksDown(var) == downlocks[v] )
7833  {
7834  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7835 
7836  if( roundable )
7837  {
7838  if( alternativelbs[v] > ub )
7839  {
7840  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7841  assert(!infeasible);
7842  assert(fixed);
7843 
7844  (*nfixedvars)++;
7845 
7846  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7847  * constraints
7848  */
7849  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7850  }
7851  else
7852  {
7853  SCIP_Bool success;
7854 
7855  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7856  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7857  * infeasible we can apply the dual reduction; otherwise we do nothing
7858  */
7859  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7860  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7861  nfixedvars, &success, cutoff) );
7862 
7863  if( success )
7864  {
7865  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7866  }
7867 
7868  }
7869  }
7870  }
7871 
7872  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7873  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7874 
7875  /* ignore fixed variables */
7876  if( ub - lb <= 0 )
7877  continue;
7878 
7879  if( SCIPvarGetNLocksUp(var) == uplocks[v] )
7880  {
7881  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7882 
7883  if( roundable )
7884  {
7885  if( alternativeubs[v] < lb )
7886  {
7887  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
7888  assert(!infeasible);
7889  assert(fixed);
7890 
7891  (*nfixedvars)++;
7892 
7893  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7894  * constraints
7895  */
7896  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7897  }
7898  else
7899  {
7900  SCIP_Bool success;
7901 
7902  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7903  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7904  * infeasible we can apply the dual reduction; otherwise we do nothing
7905  */
7906  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
7907  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7908  nfixedvars, &success, cutoff) );
7909 
7910  if( success )
7911  {
7912  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7913  }
7914  }
7915  }
7916  }
7917  }
7918 
7919  /* free temporary memory */
7920  SCIPfreeBufferArray(scip, &uppropubs);
7921  SCIPfreeBufferArray(scip, &upproplbs);
7922  SCIPfreeBufferArray(scip, &upimplubs);
7923  SCIPfreeBufferArray(scip, &upimpllbs);
7924  SCIPfreeBufferArray(scip, &downpropubs);
7925  SCIPfreeBufferArray(scip, &downproplbs);
7926  SCIPfreeBufferArray(scip, &downimplubs);
7927  SCIPfreeBufferArray(scip, &downimpllbs);
7928 
7929  return SCIP_OKAY;
7930 }
7931 
7932 /** propagate all constraints together */
7933 static
7935  SCIP* scip, /**< SCIP data structure */
7936  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7937  SCIP_CONS** conss, /**< all cumulative constraint */
7938  int nconss, /**< number of cumulative constraints */
7939  SCIP_Bool local, /**< use local bounds effective horizon? */
7940  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7941  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
7942  SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
7943  )
7944 { /*lint --e{715}*/
7945  SCIP_VAR** vars;
7946  int* downlocks;
7947  int* uplocks;
7948  int* alternativelbs;
7949  int* alternativeubs;
7950  int oldnfixedvars;
7951  int nvars;
7952  int v;
7953 
7954  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7955  return SCIP_OKAY;
7956 
7957  nvars = SCIPgetNVars(scip);
7958  oldnfixedvars = *nfixedvars;
7959 
7960  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) );
7961  SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
7962  SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
7963  SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
7964  SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
7965 
7966  /* initialize arrays */
7967  for( v = 0; v < nvars; ++v )
7968  {
7969  downlocks[v] = 0;
7970  uplocks[v] = 0;
7971  alternativelbs[v] = INT_MAX;
7972  alternativeubs[v] = INT_MIN;
7973  }
7974 
7975  /* compute alternative bounds */
7976  SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
7977 
7978  /* apply fixing which result of the alternative bounds directly */
7979  SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
7980  nfixedvars, cutoff) );
7981 
7982  if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
7983  {
7984  SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
7985  }
7986 
7987  /* free all buffers */
7988  SCIPfreeBufferArray(scip, &alternativeubs);
7989  SCIPfreeBufferArray(scip, &alternativelbs);
7990  SCIPfreeBufferArray(scip, &uplocks);
7991  SCIPfreeBufferArray(scip, &downlocks);
7992  SCIPfreeBufferArray(scip, &vars);
7993 
7994  return SCIP_OKAY;
7995 }
7996 
7997 /**@} */
7998 
7999 /**@name Linear relaxations
8000  *
8001  * @{
8002  */
8003 
8004 /** creates covering cuts for jobs violating resource constraints */
8005 static
8007  SCIP* scip, /**< SCIP data structure */
8008  SCIP_CONS* cons, /**< constraint to be checked */
8009  int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8010  int time /**< at this point in time covering constraints are valid */
8011  )
8012 {
8013  SCIP_CONSDATA* consdata;
8014  SCIP_ROW* row;
8015  int* flexibleids;
8016  int* demands;
8017 
8018  char rowname[SCIP_MAXSTRLEN];
8019 
8020  int remainingcap;
8021  int smallcoversize; /* size of a small cover */
8022  int bigcoversize; /* size of a big cover */
8023  int nvars;
8024 
8025  int nflexible;
8026  int sumdemand; /* demand of all jobs up to a certain index */
8027  int j;
8028 
8029  assert(cons != NULL);
8030 
8031  /* get constraint data structure */
8032  consdata = SCIPconsGetData(cons);
8033  assert(consdata != NULL );
8034 
8035  nvars = consdata->nvars;
8036 
8037  /* sort jobs according to demands */
8038  SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8039  SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8040 
8041  nflexible = 0;
8042  remainingcap = consdata->capacity;
8043 
8044  /* get all jobs intersecting point 'time' with their bounds */
8045  for( j = 0; j < nvars; ++j )
8046  {
8047  int ub;
8048 
8049  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8050 
8051  /* only add jobs to array if they intersect with point 'time' */
8052  if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8053  {
8054  /* if job is fixed, capacity has to be decreased */
8055  if( startvalues[j] == ub )
8056  {
8057  remainingcap -= consdata->demands[j];
8058  }
8059  else
8060  {
8061  demands[nflexible] = consdata->demands[j];
8062  flexibleids[nflexible] = j;
8063  ++nflexible;
8064  }
8065  }
8066  }
8067  assert(remainingcap >= 0);
8068 
8069  /* sort demands and job ids */
8070  SCIPsortIntInt(demands, flexibleids, nflexible);
8071 
8072  /*
8073  * version 1:
8074  * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8075  * erzeuge cover constraint
8076  *
8077  */
8078 
8079  /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8080  sumdemand = 0;
8081  j = 0;
8082 
8083  while( j < nflexible && sumdemand <= remainingcap )
8084  {
8085  sumdemand += demands[j];
8086  j++;
8087  }
8088 
8089  /* j jobs form a conflict, set coversize to 'j - 1' */
8090  bigcoversize = j-1;
8091  assert(sumdemand > remainingcap);
8092  assert(bigcoversize < nflexible);
8093 
8094  /* - create a row for all jobs and their binary variables.
8095  * - at most coversize many binary variables of jobs can be set to one
8096  */
8097 
8098  /* construct row name */
8099  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8100  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8101  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8102  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8103 
8104  for( j = 0; j < nflexible; ++j )
8105  {
8106  SCIP_VAR** binvars;
8107  int* vals;
8108  int nbinvars;
8109  int idx;
8110  int start;
8111  int end;
8112  int lb;
8113  int ub;
8114  int b;
8115 
8116  idx = flexibleids[j];
8117 
8118  /* get and add binvars into var array */
8119  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8120  assert(nbinvars != 0);
8121 
8122  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8123  assert(vals != NULL);
8124 
8125  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8126  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8127 
8128  /* compute start and finishing time */
8129  start = time - consdata->durations[idx] + 1;
8130  end = MIN(time, ub);
8131 
8132  /* add all neccessary binary variables */
8133  for( b = 0; b < nbinvars; ++b )
8134  {
8135  if( vals[b] < start || vals[b] < lb )
8136  continue;
8137 
8138  if( vals[b] > end )
8139  break;
8140 
8141  assert(binvars[b] != NULL);
8142  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8143  }
8144  }
8145 
8146  /* insert and release row */
8147  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8148 
8149  if( consdata->bcoverrowssize == 0 )
8150  {
8151  consdata->bcoverrowssize = 10;
8152  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8153  }
8154  if( consdata->nbcoverrows == consdata->bcoverrowssize )
8155  {
8156  consdata->bcoverrowssize *= 2;
8157  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8158  }
8159 
8160  consdata->bcoverrows[consdata->nbcoverrows] = row;
8161  consdata->nbcoverrows++;
8162 
8163  /*
8164  * version 2:
8165  * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8166  * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8167  */
8168  /* find maximum number of jobs that can run in parallel (= coversize -1) */
8169  sumdemand = 0;
8170  j = nflexible -1;
8171  while( sumdemand <= remainingcap )
8172  {
8173  assert(j >= 0);
8174  sumdemand += demands[j];
8175  j--;
8176  }
8177 
8178  smallcoversize = nflexible - (j + 1) - 1;
8179  while( j > 0 && demands[j] == demands[nflexible-1] )
8180  --j;
8181 
8182  assert(smallcoversize < nflexible);
8183 
8184  if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8185  {
8186  /* construct row name */
8187  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8188  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8189  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8190  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8191 
8192  /* filter binary variables for each unfixed job */
8193  for( j = j + 1; j < nflexible; ++j )
8194  {
8195  SCIP_VAR** binvars;
8196  int* vals;
8197  int nbinvars;
8198  int idx;
8199  int start;
8200  int end;
8201  int lb;
8202  int ub;
8203  int b;
8204 
8205  idx = flexibleids[j];
8206 
8207  /* get and add binvars into var array */
8208  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8209  assert(nbinvars != 0);
8210 
8211  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8212  assert(vals != NULL);
8213 
8214  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8215  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8216 
8217  /* compute start and finishing time */
8218  start = time - consdata->durations[idx] + 1;
8219  end = MIN(time, ub);
8220 
8221  /* add all neccessary binary variables */
8222  for( b = 0; b < nbinvars; ++b )
8223  {
8224  if( vals[b] < start || vals[b] < lb )
8225  continue;
8226 
8227  if( vals[b] > end )
8228  break;
8229 
8230  assert(binvars[b] != NULL);
8231  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8232  }
8233  }
8234 
8235  /* insert and release row */
8236  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8237  if( consdata->scoverrowssize == 0 )
8238  {
8239  consdata->scoverrowssize = 10;
8240  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8241  }
8242  if( consdata->nscoverrows == consdata->scoverrowssize )
8243  {
8244  consdata->scoverrowssize *= 2;
8245  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8246  }
8247 
8248  consdata->scoverrows[consdata->nscoverrows] = row;
8249  consdata->nscoverrows++;
8250  }
8251 
8252  /* free buffer arrays */
8253  SCIPfreeBufferArray(scip, &flexibleids);
8254  SCIPfreeBufferArray(scip, &demands);
8255 
8256  return SCIP_OKAY;
8257 }
8258 
8259 /** method to construct cover cuts for all points in time */
8260 static
8262  SCIP* scip, /**< SCIP data structure */
8263  SCIP_CONS* cons /**< constraint to be separated */
8264  )
8265 {
8266  SCIP_CONSDATA* consdata;
8267 
8268  int* startvalues; /* stores when each job is starting */
8269  int* endvalues; /* stores when each job ends */
8270  int* startvaluessorted; /* stores when each job is starting */
8271  int* endvaluessorted; /* stores when each job ends */
8272  int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8273  int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8274 
8275  int nvars; /* number of jobs for this constraint */
8276  int freecapacity; /* remaining capacity */
8277  int curtime; /* point in time which we are just checking */
8278  int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8279 
8280  int hmin;
8281  int hmax;
8282 
8283  int j;
8284  int t;
8285 
8286  assert(scip != NULL);
8287  assert(cons != NULL);
8288 
8289  consdata = SCIPconsGetData(cons);
8290  assert(consdata != NULL);
8291 
8292  /* if no activities are associated with this resource then this constraint is redundant */
8293  if( consdata->vars == NULL )
8294  return SCIP_OKAY;
8295 
8296  nvars = consdata->nvars;
8297  hmin = consdata->hmin;
8298  hmax = consdata->hmax;
8299 
8300  SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8301  SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8302  SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8303  SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8304  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8305  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8306 
8307  /* assign start and endpoints to arrays */
8308  for ( j = 0; j < nvars; ++j )
8309  {
8310  startvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8311  startvaluessorted[j] = startvalues[j];
8312 
8313  endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8314  endvaluessorted[j] = endvalues[j];
8315 
8316  startindices[j] = j;
8317  endindices[j] = j;
8318  }
8319 
8320  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8321  * (and sort the indices in the same way) */
8322  SCIPsortIntInt(startvaluessorted, startindices, nvars);
8323  SCIPsortIntInt(endvaluessorted, endindices, nvars);
8324 
8325  endidx = 0;
8326  freecapacity = consdata->capacity;
8327 
8328  /* check each startpoint of a job whether the capacity is kept or not */
8329  for( j = 0; j < nvars; ++j )
8330  {
8331  curtime = startvaluessorted[j];
8332  if( curtime >= hmax )
8333  break;
8334 
8335  /* subtract all capacity needed up to this point */
8336  freecapacity -= consdata->demands[startindices[j]];
8337 
8338  while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8339  {
8340  ++j;
8341  freecapacity -= consdata->demands[startindices[j]];
8342  }
8343 
8344  /* free all capacity usages of jobs the are no longer running */
8345  while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8346  {
8347  freecapacity += consdata->demands[endindices[endidx]];
8348  ++endidx;
8349  }
8350 
8351  assert(freecapacity <= consdata->capacity);
8352  assert(endidx <= nvars);
8353 
8354  /* --> endindex - points to the next job which will finish
8355  * j - points to the last job that has been released
8356  */
8357 
8358 
8359  /* check freecapacity to be smaller than zero
8360  * then we will add cover constraints to the MIP
8361  */
8362  if( freecapacity < 0 && curtime >= hmin )
8363  {
8364  int nextprofilechange;
8365 
8366  /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8367  if( j < nvars-1 )
8368  nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8369  else
8370  nextprofilechange = endvaluessorted[endidx];
8371 
8372  nextprofilechange = MIN(nextprofilechange, hmax);
8373 
8374  for( t = curtime; t < nextprofilechange; ++t )
8375  {
8376  SCIPdebugMessage("add cover constraint for time %d\n", curtime);
8377 
8378  /* create covering constraint */
8379  SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8380 
8381  }
8382  } /* end if freecapacity > 0 */
8383 
8384  } /*lint --e{850}*/
8385 
8386  consdata->covercuts = TRUE;
8387 
8388  /* free all buffer arrays */
8389  SCIPfreeBufferArray(scip, &endindices);
8390  SCIPfreeBufferArray(scip, &startindices);
8391  SCIPfreeBufferArray(scip, &endvaluessorted);
8392  SCIPfreeBufferArray(scip, &startvaluessorted);
8393  SCIPfreeBufferArray(scip, &endvalues);
8394  SCIPfreeBufferArray(scip, &startvalues);
8395 
8396  return SCIP_OKAY;
8397 }
8398 
8399 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8400  * constraint
8401  */
8402 static
8404  SCIP* scip, /**< SCIP data structure */
8405  SCIP_CONS* cons, /**< constraint to be checked */
8406  int* startindices, /**< permutation with rspect to the start times */
8407  int curtime, /**< current point in time */
8408  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8409  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8410  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8411  )
8412 {
8413  SCIP_CONSDATA* consdata;
8414  SCIP_VAR** binvars;
8415  int* coefs;
8416  int nbinvars;
8417  char name[SCIP_MAXSTRLEN];
8418  int capacity;
8419  int b;
8420 
8421  assert(nstarted > nfinished);
8422 
8423  consdata = SCIPconsGetData(cons);
8424  assert(consdata != NULL);
8425  assert(consdata->nvars > 0);
8426 
8427  capacity = consdata->capacity;
8428  assert(capacity > 0);
8429 
8430  nbinvars = 0;
8431  SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8432 
8433  /* construct row name */
8434  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8435 
8436  if( cutsasconss )
8437  {
8438  SCIP_CONS* lincons;
8439 
8440  /* create knapsack constraint for the given time point */
8441  SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8442  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) );
8443 
8444  for( b = 0; b < nbinvars; ++b )
8445  {
8446  SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8447  }
8448 
8449  /* add and release the new constraint */
8450  SCIP_CALL( SCIPaddCons(scip, lincons) );
8451  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8452  }
8453  else
8454  {
8455  SCIP_ROW* row;
8456 
8457  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8458  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8459 
8460  for( b = 0; b < nbinvars; ++b )
8461  {
8462  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8463  }
8464 
8465  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8466  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8467 
8468  if( consdata->demandrowssize == 0 )
8469  {
8470  consdata->demandrowssize = 10;
8471  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8472  }
8473  if( consdata->ndemandrows == consdata->demandrowssize )
8474  {
8475  consdata->demandrowssize *= 2;
8476  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8477  }
8478 
8479  consdata->demandrows[consdata->ndemandrows] = row;
8480  consdata->ndemandrows++;
8481  }
8482 
8483  SCIPfreeBufferArrayNull(scip, &binvars);
8484  SCIPfreeBufferArrayNull(scip, &coefs);
8485 
8486  return SCIP_OKAY;
8487 }
8488 
8489 /** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8490  * row
8491  */
8492 static
8494  SCIP* scip, /**< SCIP data structure */
8495  SCIP_CONS* cons, /**< constraint to be checked */
8496  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8497  )
8498 {
8499  SCIP_CONSDATA* consdata;
8500 
8501  int* starttimes; /* stores when each job is starting */
8502  int* endtimes; /* stores when each job ends */
8503  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8504  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8505 
8506  int nvars; /* number of activities for this constraint */
8507  int freecapacity; /* remaining capacity */
8508  int curtime; /* point in time which we are just checking */
8509  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8510 
8511  int hmin;
8512  int hmax;
8513 
8514  int j;
8515 
8516  assert(scip != NULL);
8517  assert(cons != NULL);
8518 
8519  consdata = SCIPconsGetData(cons);
8520  assert(consdata != NULL);
8521 
8522  nvars = consdata->nvars;
8523 
8524  /* if no activities are associated with this cumulative then this constraint is redundant */
8525  if( nvars == 0 )
8526  return SCIP_OKAY;
8527 
8528  assert(consdata->vars != NULL);
8529 
8530  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8531  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8532  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8533  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8534 
8535  SCIPdebugMessage("create sorted event points for cumulative constraint <%s> with %d jobs\n",
8536  SCIPconsGetName(cons), nvars);
8537 
8538  /* create event point arrays */
8539  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8540  starttimes, endtimes, startindices, endindices, FALSE);
8541 
8542  endindex = 0;
8543  freecapacity = consdata->capacity;
8544  hmin = consdata->hmin;
8545  hmax = consdata->hmax;
8546 
8547  /* check each startpoint of a job whether the capacity is kept or not */
8548  for( j = 0; j < nvars; ++j )
8549  {
8550  curtime = starttimes[j];
8551  SCIPdebugMessage("look at %d-th job with start %d\n", j, curtime);
8552 
8553  if( curtime >= hmax )
8554  break;
8555 
8556  /* remove the capacity requirments for all job which start at the curtime */
8557  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8558 
8559  /* add the capacity requirments for all job which end at the curtime */
8560  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8561 
8562  assert(freecapacity <= consdata->capacity);
8563  assert(endindex <= nvars);
8564 
8565  /* endindex - points to the next job which will finish */
8566  /* j - points to the last job that has been released */
8567 
8568  /* if free capacity is smaller than zero, then add rows to the LP */
8569  if( freecapacity < 0 && curtime >= hmin )
8570  {
8571  int nextstarttime;
8572  int t;
8573 
8574  /* step forward until next job is released and see whether capacity constraint is met or not */
8575  if( j < nvars-1 )
8576  nextstarttime = starttimes[j+1];
8577  else
8578  nextstarttime = endtimes[nvars-1];
8579 
8580  nextstarttime = MIN(nextstarttime, hmax);
8581 
8582  /* create capacity restriction row for current event point */
8583  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8584 
8585  /* create for all points in time between the current event point and next start event point a row if the free
8586  * capacity is still smaller than zero */
8587  for( t = curtime+1 ; t < nextstarttime; ++t )
8588  {
8589  /* add the capacity requirments for all job which end at the curtime */
8590  addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8591 
8592  if( freecapacity < 0 )
8593  {
8594  /* add constraint */
8595  SCIPdebugMessage("add capacity constraint at time %d\n", t);
8596 
8597  /* create capacity restriction row */
8598  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8599  }
8600  else
8601  break;
8602  }
8603  }
8604  } /*lint --e{850}*/
8605 
8606  /* free all buffer arrays */
8607  SCIPfreeBufferArray(scip, &endindices);
8608  SCIPfreeBufferArray(scip, &startindices);
8609  SCIPfreeBufferArray(scip, &endtimes);
8610  SCIPfreeBufferArray(scip, &starttimes);
8611 
8612  return SCIP_OKAY;
8613 }
8614 
8615 /** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8616  * capacity is larger than the capacity of the cumulative constraint
8617  * - for each necessary point in time:
8618  *
8619  * sum_j sum_t demand_j * x_{j,t} <= capacity
8620  *
8621  * where x(j,t) is the binary variables of job j at time t
8622  */
8623 static
8625  SCIP* scip, /**< SCIP data structure */
8626  SCIP_CONS* cons, /**< cumulative constraint */
8627  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8628  )
8629 {
8630  SCIP_CONSDATA* consdata;
8631 
8632  consdata = SCIPconsGetData(cons);
8633  assert(consdata != NULL);
8634  assert(consdata->demandrows == NULL);
8635  assert(consdata->ndemandrows == 0);
8636 
8637  /* collect the linking constraints */
8638  if( consdata->linkingconss == NULL )
8639  {
8640  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8641  }
8642 
8643  SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8644 
8645  /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8646  if( cutsasconss )
8647  {
8648  if( SCIPconsIsInitial(cons) )
8649  {
8650  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
8651  }
8652  if( SCIPconsIsSeparated(cons) )
8653  {
8654  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
8655  }
8656  if( SCIPconsIsEnforced(cons) )
8657  {
8658  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
8659  }
8660  }
8661 
8662  return SCIP_OKAY;
8663 }
8664 
8665 /** adds linear relaxation of cumulative constraint to the LP */
8666 static
8668  SCIP* scip, /**< SCIP data structure */
8669  SCIP_CONS* cons, /**< cumulative constraint */
8670  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8671  )
8672 {
8673  SCIP_CONSDATA* consdata;
8674  int r;
8675 
8676  consdata = SCIPconsGetData(cons);
8677  assert(consdata != NULL);
8678 
8679  if( consdata->demandrows == NULL )
8680  {
8681  SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8682  }
8683 
8684  for( r = 0; r < consdata->ndemandrows; ++r )
8685  {
8686  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8687  {
8688  SCIP_Bool infeasible;
8689 
8690  assert(consdata->demandrows[r] != NULL);
8691  SCIP_CALL( SCIPaddCut(scip, NULL, consdata->demandrows[r], FALSE, &infeasible) );
8692  assert( ! infeasible ); /* this function is only called by initlp -> the cut should be feasible */
8693  }
8694  }
8695 
8696  return SCIP_OKAY;
8697 }
8698 
8699 /** checks constraint for violation, and adds it as a cut if possible */
8700 static
8702  SCIP* scip, /**< SCIP data structure */
8703  SCIP_CONS* cons, /**< cumulative constraint to be separated */
8704  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8705  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8706  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8707  )
8708 { /*lint --e{715}*/
8709  SCIP_CONSDATA* consdata;
8710  int ncuts;
8711  int r;
8712 
8713  assert(scip != NULL);
8714  assert(cons != NULL);
8715  assert(separated != NULL);
8716  assert(cutoff != NULL);
8717 
8718  *separated = FALSE;
8719  *cutoff = FALSE;
8720 
8721  consdata = SCIPconsGetData(cons);
8722  assert(consdata != NULL);
8723 
8724  SCIPdebugMessage("separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8725 
8726  if( consdata->demandrows == NULL )
8727  {
8728  SCIP_CALL( createRelaxation(scip, cons, FALSE) );
8729  }
8730 
8731  ncuts = 0;
8732 
8733  /* check each row that is not contained in LP */
8734  for( r = 0; r < consdata->ndemandrows; ++r )
8735  {
8736  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8737  {
8738  SCIP_Real feasibility;
8739 
8740  if( sol != NULL )
8741  feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8742  else
8743  feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8744 
8745  if( SCIPisFeasNegative(scip, feasibility) )
8746  {
8747  SCIP_CALL( SCIPaddCut(scip, sol, consdata->demandrows[r], FALSE, cutoff) );
8748  if ( *cutoff )
8749  {
8750  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8751  return SCIP_OKAY;
8752  }
8753  *separated = TRUE;
8754  ncuts++;
8755  }
8756  }
8757  }
8758 
8759  if( ncuts > 0 )
8760  {
8761  SCIPdebugMessage("cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8762 
8763  /* if successful, reset age of constraint */
8764  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8765  (*separated) = TRUE;
8766  }
8767 
8768  return SCIP_OKAY;
8769 }
8770 
8771 /** checks constraint for violation, and adds it as a cut if possible */
8772 static
8774  SCIP* scip, /**< SCIP data structure */
8775  SCIP_CONS* cons, /**< logic or constraint to be separated */
8776  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8777  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8778  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8779  )
8780 {
8781  SCIP_CONSDATA* consdata;
8782  SCIP_ROW* row;
8783  SCIP_Real minfeasibility;
8784  int r;
8785 
8786  assert(scip != NULL);
8787  assert(cons != NULL);
8788  assert(separated != NULL);
8789  assert(cutoff != NULL);
8790 
8791  *separated = FALSE;
8792  *cutoff = FALSE;
8793 
8794  consdata = SCIPconsGetData(cons);
8795  assert(consdata != NULL);
8796 
8797  SCIPdebugMessage("separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8798 
8799  /* collect the linking constraints */
8800  if( consdata->linkingconss == NULL )
8801  {
8802  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8803  }
8804 
8805  if( !consdata->covercuts )
8806  {
8807  SCIP_CALL( createCoverCuts(scip, cons) );
8808  }
8809 
8810  row = NULL;
8811  minfeasibility = SCIPinfinity(scip);
8812 
8813  /* check each row of small covers that is not contained in LP */
8814  for( r = 0; r < consdata->nscoverrows; ++r )
8815  {
8816  if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8817  {
8818  SCIP_Real feasibility;
8819 
8820  assert(consdata->scoverrows[r] != NULL);
8821  if( sol != NULL )
8822  feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8823  else
8824  feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8825 
8826  if( minfeasibility > feasibility )
8827  {
8828  minfeasibility = feasibility;
8829  row = consdata->scoverrows[r];
8830  }
8831  }
8832  }
8833 
8834  if( SCIPisFeasNegative(scip, minfeasibility) )
8835  {
8836  SCIPdebugMessage("cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8837  SCIPconsGetName(cons), minfeasibility);
8838 
8839  assert(row != NULL);
8840  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, cutoff) );
8841  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8842  if ( *cutoff )
8843  return SCIP_OKAY;
8844  (*separated) = TRUE;
8845  }
8846 
8847  minfeasibility = SCIPinfinity(scip);
8848  row = NULL;
8849 
8850  /* check each row of small covers that is not contained in LP */
8851  for( r = 0; r < consdata->nbcoverrows; ++r )
8852  {
8853  if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8854  {
8855  SCIP_Real feasibility;
8856 
8857  assert(consdata->bcoverrows[r] != NULL);
8858  if( sol != NULL )
8859  feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8860  else
8861  feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8862 
8863  if( minfeasibility > feasibility )
8864  {
8865  minfeasibility = feasibility;
8866  row = consdata->bcoverrows[r];
8867  }
8868  }
8869  }
8870 
8871  if( SCIPisFeasNegative(scip, minfeasibility) )
8872  {
8873  SCIPdebugMessage("cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8874  SCIPconsGetName(cons), minfeasibility);
8875 
8876  assert(row != NULL);
8877  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, cutoff) );
8878  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8879  if ( *cutoff )
8880  return SCIP_OKAY;
8881  (*separated) = TRUE;
8882  }
8883 
8884  return SCIP_OKAY;
8885 }
8886 
8887 /** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
8888 static
8890  SCIP* scip, /**< SCIP data structure */
8891  SCIP_CONS* cons, /**< constraint to be checked */
8892  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8893  int* startindices, /**< permutation with rspect to the start times */
8894  int curtime, /**< current point in time */
8895  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8896  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8897  SCIP_Bool lower /**< shall cuts be created due to lower or upper bounds? */
8898  )
8899 {
8900  SCIP_CONSDATA* consdata;
8901  char name[SCIP_MAXSTRLEN];
8902  SCIP_Bool infeasible;
8903  int lhs; /* left hand side of constraint */
8904 
8905  SCIP_VAR** activevars;
8906  SCIP_ROW* row;
8907 
8908  int v;
8909 
8910  assert(nstarted > nfinished);
8911 
8912  consdata = SCIPconsGetData(cons);
8913  assert(consdata != NULL);
8914  assert(consdata->nvars > 0);
8915 
8916 
8917  SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
8918 
8919  SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
8920 
8921  if( lower )
8922  {
8923  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
8924 
8925  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, (SCIP_Real) lhs, SCIPinfinity(scip),
8926  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8927  }
8928  else
8929  {
8930  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
8931  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real) lhs,
8932  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
8933  }
8934 
8935  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8936 
8937  for( v = 0; v < nstarted - nfinished; ++v )
8938  {
8939  SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
8940  }
8941 
8942  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8943  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8944 
8945  SCIP_CALL( SCIPaddCut(scip, sol, row, TRUE, &infeasible) );
8946  assert( ! infeasible );
8947 
8948  SCIP_CALL( SCIPreleaseRow(scip, &row) );
8949 
8950  /* free buffers */
8951  SCIPfreeBufferArrayNull(scip, &activevars);
8952 
8953  return SCIP_OKAY;
8954 }
8955 
8956 /** checks constraint for violation, and adds it as a cut if possible */
8957 static
8959  SCIP* scip, /**< SCIP data structure */
8960  SCIP_CONS* cons, /**< cumulative constraint to be separated */
8961  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8962  SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
8963  SCIP_Bool* separated /**< pointer to store TRUE, if a cut was found */
8964  )
8965 {
8966 
8967  SCIP_CONSDATA* consdata;
8968 
8969  int* starttimes; /* stores when each job is starting */
8970  int* endtimes; /* stores when each job ends */
8971  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8972  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8973 
8974  int nvars; /* number of activities for this constraint */
8975  int freecapacity; /* remaining capacity */
8976  int curtime; /* point in time which we are just checking */
8977  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8978 
8979  int hmin;
8980  int hmax;
8981  int j;
8982 
8983  assert(scip != NULL);
8984  assert(cons != NULL);
8985 
8986  consdata = SCIPconsGetData(cons);
8987  assert(consdata != NULL);
8988 
8989  nvars = consdata->nvars;
8990 
8991  /* if no activities are associated with this cumulative then this constraint is redundant */
8992  if( nvars <= 1 )
8993  return SCIP_OKAY;
8994 
8995  assert(consdata->vars != NULL);
8996 
8997  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8998  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8999  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9000  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9001 
9002  SCIPdebugMessage("create sorted event points for cumulative constraint <%s> with %d jobs\n",
9003  SCIPconsGetName(cons), nvars);
9004 
9005  /* create event point arrays */
9006  createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9007 
9008  /* now nvars might be smaller than before! */
9009 
9010  endindex = 0;
9011  freecapacity = consdata->capacity;
9012  hmin = consdata->hmin;
9013  hmax = consdata->hmax;
9014 
9015  /* check each startpoint of a job whether the capacity is kept or not */
9016  for( j = 0; j < nvars; ++j )
9017  {
9018  curtime = starttimes[j];
9019 
9020  if( curtime >= hmax )
9021  break;
9022 
9023  /* remove the capacity requirements for all job which start at the curtime */
9024  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9025 
9026  /* add the capacity requirments for all job which end at the curtime */
9027  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9028 
9029  assert(freecapacity <= consdata->capacity);
9030  assert(endindex <= nvars);
9031 
9032  /* endindex - points to the next job which will finish */
9033  /* j - points to the last job that has been released */
9034 
9035  /* if free capacity is smaller than zero, then add rows to the LP */
9036  if( freecapacity < 0 && curtime >= hmin)
9037  {
9038  /* create capacity restriction row for current event point */
9039  SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, sol, startindices, curtime, j+1, endindex, lower) );
9040  *separated = TRUE;
9041  }
9042  } /*lint --e{850}*/
9043 
9044  /* free all buffer arrays */
9045  SCIPfreeBufferArray(scip, &endindices);
9046  SCIPfreeBufferArray(scip, &startindices);
9047  SCIPfreeBufferArray(scip, &endtimes);
9048  SCIPfreeBufferArray(scip, &starttimes);
9049 
9050  return SCIP_OKAY;
9051 }
9052 
9053 /**@} */
9054 
9055 
9056 /**@name Presolving
9057  *
9058  * @{
9059  */
9060 
9061 #ifndef NDEBUG
9062 /** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9063  * correct
9064  */
9065 static
9067  SCIP* scip, /**< SCIP data structure */
9068  SCIP_CONS* cons /**< constraint to be checked */
9069  )
9070 {
9071  SCIP_CONSDATA* consdata;
9072  int capacity;
9073  int nvars;
9074  int j;
9075 
9076  assert(scip != NULL);
9077  assert(cons != NULL);
9078 
9079  consdata = SCIPconsGetData(cons);
9080  assert(consdata != NULL);
9081 
9082  nvars = consdata->nvars;
9083 
9084  /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9085  if( nvars <= 1 )
9086  return TRUE;
9087 
9088  assert(consdata->vars != NULL);
9089  capacity = consdata->capacity;
9090 
9091  /* check each activity: if demand is larger than capacity the problem is infeasible */
9092  for ( j = 0; j < nvars; ++j )
9093  {
9094  if( consdata->demands[j] > capacity )
9095  return FALSE;
9096  }
9097 
9098  return TRUE;
9099 }
9100 #endif
9101 
9102 /** delete constraint if it consists of at most one job
9103  *
9104  * @todo this method needs to be adjusted w.r.t. effective horizon
9105  */
9106 static
9108  SCIP* scip, /**< SCIP data structure */
9109  SCIP_CONS* cons, /**< constraint to propagate */
9110  int* ndelconss, /**< pointer to store the number of deleted constraints */
9111  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9112  )
9113 {
9114  SCIP_CONSDATA* consdata;
9115 
9116  assert(scip != NULL);
9117  assert(cons != NULL);
9118 
9119  consdata = SCIPconsGetData(cons);
9120  assert(consdata != NULL);
9121 
9122  if( consdata->nvars == 0 )
9123  {
9124  SCIPdebugMessage("delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9125 
9126  SCIP_CALL( SCIPdelCons(scip, cons) );
9127  (*ndelconss)++;
9128  }
9129  else if( consdata->nvars == 1 )
9130  {
9131  if( consdata->demands[0] > consdata->capacity )
9132  (*cutoff) = TRUE;
9133  else
9134  {
9135  SCIPdebugMessage("delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9136 
9137  SCIP_CALL( SCIPdelCons(scip, cons) );
9138  (*ndelconss)++;
9139  }
9140  }
9141 
9142  return SCIP_OKAY;
9143 }
9144 
9145 /** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9146  * this is done in the SCIP_DECL_CONSINITPRE() callback
9147  */
9148 static
9150  SCIP* scip, /**< SCIP data structure */
9151  SCIP_CONS* cons /**< constraint to propagate */
9152  )
9153 {
9154  SCIP_CONSDATA* consdata;
9155  SCIP_VAR* var;
9156  int demand;
9157  int duration;
9158  int hmin;
9159  int hmax;
9160  int est;
9161  int lct;
9162  int j;
9163 
9164  assert(scip != NULL);
9165  assert(cons != NULL);
9166 
9167  consdata = SCIPconsGetData(cons);
9168  assert(consdata != NULL);
9169 
9170  hmin = consdata->hmin;
9171  hmax = consdata->hmax;
9172 
9173  SCIPdebugMessage("check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9174  SCIPconsGetName(cons), hmin, hmax);
9175 
9176  for( j = consdata->nvars-1; j >= 0; --j )
9177  {
9178  var = consdata->vars[j];
9179  demand = consdata->demands[j];
9180  duration = consdata->durations[j];
9181 
9182  /* earliest completion time (ect) and latest start time (lst) */
9183  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9184  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9185 
9186  if( demand == 0 || duration == 0 )
9187  {
9188  /* jobs with zero demand or zero duration can be removed */
9189  SCIPdebugMessage(" remove variable <%s> due to zero %s\n",
9190  SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9191 
9192  /* remove variable form constraint */
9193  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9194  }
9195  else if( est >= hmax || lct <= hmin )
9196  {
9197  SCIPdebugMessage(" remove variable <%s>[%d,%d] with duration <%d>\n",
9198  SCIPvarGetName(var), est, lct - duration, duration);
9199 
9200  /* delete variable at the given position */
9201  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9202 
9203  /* for the statistic we count the number of jobs which are irrelevant */
9204  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9205  }
9206  }
9207 
9208  return SCIP_OKAY;
9209 }
9210 
9211 /** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9212 static
9214  SCIP* scip, /**< SCIP data structure */
9215  SCIP_CONSDATA* consdata, /**< constraint data */
9216  int pos, /**< position of job in the consdata */
9217  int* nchgbds, /**< pointer to store the number of changed bounds */
9218  int* naddconss, /**< pointer to store the number of added constraints */
9219  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9220  )
9221 {
9222  SCIP_VAR* var;
9223  SCIP_Bool tightened;
9224  int duration;
9225  int ect;
9226  int lst;
9227 
9228  assert(scip != NULL);
9229 
9230  /* zero energy jobs should be removed already */
9231  assert(consdata->durations[pos] > 0);
9232  assert(consdata->demands[pos] > 0);
9233 
9234  var = consdata->vars[pos];
9235  assert(var != NULL);
9236  duration = consdata->durations[pos];
9237 
9238  /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9239  SCIPdebugMessage(" variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9240  SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9241 
9242  /* earliest completion time (ect) and latest start time (lst) */
9243  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9244  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9245 
9246  /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9247  if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9248  return SCIP_OKAY;
9249 
9250  if( ect > consdata->hmin && lst < consdata->hmax )
9251  {
9252  /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9253  *cutoff = TRUE;
9254  }
9255  else if( lst < consdata->hmax )
9256  {
9257  /* move the latest start time of this job in such a way that it finishes before or at hmin */
9258  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9259  assert(tightened);
9260  assert(!(*cutoff));
9261  (*nchgbds)++;
9262  }
9263  else if( ect > consdata->hmin )
9264  {
9265  /* move the earliest start time of this job in such a way that it starts after or at hmax */
9266  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9267  assert(tightened);
9268  assert(!(*cutoff));
9269  (*nchgbds)++;
9270  }
9271  else
9272  {
9273  /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9274  * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9275  *
9276  * (var <= hmin - duration) /\ (var >= hmax)
9277  */
9278  SCIP_CONS* cons;
9279 
9280  SCIP_VAR* vartuple[2];
9281  SCIP_BOUNDTYPE boundtypetuple[2];
9282  SCIP_Real boundtuple[2];
9283 
9284  char name[SCIP_MAXSTRLEN];
9285  int leftbound;
9286  int rightbound;
9287 
9288  leftbound = consdata->hmin - duration;
9289  rightbound = consdata->hmax;
9290 
9291  /* allocate temporary memory for arrays */
9292  vartuple[0] = var;
9293  vartuple[1] = var;
9294  boundtuple[0] = (SCIP_Real)leftbound;
9295  boundtuple[1] = (SCIP_Real)rightbound;
9296  boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9297  boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9298 
9299  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9300  SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9301 
9302  /* create and add bounddisjunction constraint */
9303  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9304  TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9305 
9306  SCIPdebugPrintCons(scip, cons, NULL);
9307 
9308  /* add and release the new constraint */
9309  SCIP_CALL( SCIPaddCons(scip, cons) );
9310  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9311  (*naddconss)++;
9312  }
9313 
9314  return SCIP_OKAY;
9315 }
9316 
9317 /** try to removed over sizeed jobs (the demand is larger than the capacity) */
9318 static
9320  SCIP* scip, /**< SCIP data structure */
9321  SCIP_CONS* cons, /**< constraint */
9322  int* nchgbds, /**< pointer to store the number of changed bounds */
9323  int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9324  int* naddconss, /**< pointer to store the number of added constraints */
9325  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9326  )
9327 {
9328  SCIP_CONSDATA* consdata;
9329  int capacity;
9330  int j;
9331 
9332  consdata = SCIPconsGetData(cons);
9333  assert(consdata != NULL);
9334 
9335  /* if a cutoff was already detected just return */
9336  if( *cutoff )
9337  return SCIP_OKAY;
9338 
9339  capacity = consdata->capacity;
9340 
9341  for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9342  {
9343  if( consdata->demands[j] > capacity )
9344  {
9345  SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9346 
9347  /* remove variable form constraint */
9348  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9349  (*nchgcoefs)++;
9350  }
9351  }
9352 
9353  SCIPdebugMessage("cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9354 
9355  return SCIP_OKAY;
9356 }
9357 
9358 /** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9359 static
9361  SCIP* scip, /**< SCIP data structure */
9362  SCIP_VAR* var, /**< integer variable to fix */
9363  SCIP_Bool uplock, /**< has thet start time variable a up lock */
9364  int* nfixedvars /**< pointer to store the number fixed variables */
9365  )
9366 {
9367  SCIP_Bool infeasible;
9368  SCIP_Bool tightened;
9369  SCIP_Bool roundable;
9370 
9371  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9372  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9373  */
9374  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9375  return SCIP_OKAY;
9376 
9377  /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9378  * handler is the only one locking that variable up
9379  */
9380  assert(uplock == TRUE || uplock == FALSE);
9381  assert((int)TRUE == 1);
9382  assert((int)FALSE == 0);
9383 
9384  if( SCIPvarGetNLocksUp(var) > (int)(uplock) )
9385  return SCIP_OKAY;
9386 
9387  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9388 
9389  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9390  * (the transformed problem is always a minimization problem)
9391  */
9392  if( !roundable )
9393  return SCIP_OKAY;
9394 
9395  SCIPdebugMessage("try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9397 
9398  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9399  assert(!infeasible);
9400 
9401  if( tightened )
9402  {
9403  SCIPdebugMessage("fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9404  (*nfixedvars)++;
9405  }
9406 
9407  return SCIP_OKAY;
9408 }
9409 
9410 /** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9411 static
9413  SCIP* scip, /**< SCIP data structure */
9414  SCIP_VAR* var, /**< integer variable to fix */
9415  SCIP_Bool downlock, /**< has the variable a down lock */
9416  int* nfixedvars /**< pointer to store the number fixed variables */
9417  )
9418 {
9419  SCIP_Bool infeasible;
9420  SCIP_Bool tightened;
9421  SCIP_Bool roundable;
9422 
9423  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9424  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9425  */
9426  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9427  return SCIP_OKAY;
9428 
9429  /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9430  * handler is the only one locking that variable down
9431  */
9432  assert(downlock == TRUE || downlock == FALSE);
9433  assert((int)TRUE == 1);
9434  assert((int)FALSE == 0);
9435 
9436  if( SCIPvarGetNLocksDown(var) > (int)(downlock) )
9437  return SCIP_OKAY;
9438 
9439  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9440 
9441  /* is it possible, to round variable down w.r.t. objective function? */
9442  if( !roundable )
9443  return SCIP_OKAY;
9444 
9445  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9446  assert(!infeasible);
9447 
9448  if( tightened )
9449  {
9450  SCIPdebugMessage("fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9451  (*nfixedvars)++;
9452  }
9453 
9454  return SCIP_OKAY;
9455 }
9456 
9457 /** normalize cumulative condition */
9458 static
9460  SCIP* scip, /**< SCIP data structure */
9461  int nvars, /**< number of start time variables (activities) */
9462  SCIP_VAR** vars, /**< array of start time variables */
9463  int* durations, /**< array of durations */
9464  int* demands, /**< array of demands */
9465  int* capacity, /**< pointer to store the changed cumulative capacity */
9466  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9467  int* nchgsides /**< pointer to count number of side changes */
9468  )
9469 { /*lint --e{715}*/
9470  SCIP_Longint gcd;
9471  int mindemand1;
9472  int mindemand2;
9473  int v;
9474 
9475  if( *capacity == 1 || nvars <= 1 )
9476  return SCIP_OKAY;
9477 
9478  assert(demands[nvars-1] <= *capacity);
9479  assert(demands[nvars-2] <= *capacity);
9480 
9481  gcd = (SCIP_Longint)demands[nvars-1];
9482  mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9483  mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9484 
9485  for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9486  {
9487  assert(mindemand1 <= mindemand2);
9488  assert(demands[v] <= *capacity);
9489 
9490  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9491 
9492  if( mindemand1 > demands[v] )
9493  {
9494  mindemand2 = mindemand1;
9495  mindemand1 = demands[v];
9496  }
9497  else if( mindemand2 > demands[v] )
9498  mindemand2 = demands[v];
9499  }
9500 
9501  if( mindemand1 + mindemand2 > *capacity )
9502  {
9503  SCIPdebugMessage("update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9504 
9505  for( v = 0; v < nvars; ++v )
9506  demands[v] = 1;
9507 
9508  (*capacity) = 1;
9509 
9510  (*nchgcoefs) += nvars;
9511  (*nchgsides)++;
9512  }
9513  else if( gcd >= 2 )
9514  {
9515  SCIPdebugMessage("cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9516 
9517  for( v = 0; v < nvars; ++v )
9518  demands[v] /= gcd;
9519 
9520  (*capacity) /= gcd;
9521 
9522  (*nchgcoefs) += nvars;
9523  (*nchgsides)++;
9524  }
9525 
9526  return SCIP_OKAY;
9527 }
9528 
9529 /** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9530  * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9531  * capacity since in that case none of the jobs can run in parallel
9532  */
9533 static
9535  SCIP* scip, /**< SCIP data structure */
9536  SCIP_CONS* cons, /**< cumulative constraint */
9537  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9538  int* nchgsides /**< pointer to count number of side changes */
9539  )
9540 {
9541  SCIP_CONSDATA* consdata;
9542  int capacity;
9543 
9544  assert(nchgcoefs != NULL);
9545  assert(nchgsides != NULL);
9546  assert(!SCIPconsIsModifiable(cons));
9547 
9548  consdata = SCIPconsGetData(cons);
9549  assert(consdata != NULL);
9550 
9551  if( consdata->normalized )
9552  return SCIP_OKAY;
9553 
9554  capacity = consdata->capacity;
9555 
9556  /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9557 
9558  SCIP_CALL( normalizeCumulativeCondition(scip, consdata->nvars, consdata->vars, consdata->durations,
9559  consdata->demands, &consdata->capacity, nchgcoefs, nchgsides) );
9560 
9561  consdata->normalized = TRUE;
9562 
9563  if( capacity > consdata->capacity )
9564  consdata->varbounds = FALSE;
9565 
9566  return SCIP_OKAY;
9567 }
9568 
9569 /** computes for the given cumulative condition the effective horizon */
9570 static
9572  SCIP* scip, /**< SCIP data structure */
9573  int nvars, /**< number of variables (jobs) */
9574  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9575  int* durations, /**< array containing corresponding durations */
9576  int* demands, /**< array containing corresponding demands */
9577  int capacity, /**< available cumulative capacity */
9578  int* hmin, /**< pointer to store the left bound of the effective horizon */
9579  int* hmax, /**< pointer to store the right bound of the effective horizon */
9580  int* split /**< point were the cumulative condition can be split */
9581  )
9582 {
9583  SCIP_PROFILE* profile;
9584 
9585  /* create empty resource profile with infinity resource capacity */
9586  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9587 
9588  /* create worst case resource profile */
9589  SCIP_CALL( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands) );
9590 
9591  /* print resource profile in if SCIP_DEBUG is defined */
9592  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
9593 
9594  /* computes the first time point where the resource capacity can be violated */
9595  (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9596 
9597  /* computes the first time point where the resource capacity is satisfied for sure */
9598  (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9599 
9600  (*split) = (*hmax);
9601 
9602  if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9603  {
9604  int* timepoints;
9605  int* loads;
9606  int ntimepoints;
9607  int t;
9608 
9609  /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9610  * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9611  * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9612  * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9613  * explain the certain "old" bound changes
9614  */
9615 
9616  /* search for time points */
9617  ntimepoints = SCIPprofileGetNTimepoints(profile);
9618  timepoints = SCIPprofileGetTimepoints(profile);
9619  loads = SCIPprofileGetLoads(profile);
9620 
9621  /* 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 */
9622  for( t = 0; t < ntimepoints; ++t )
9623  {
9624  /* ignore all time points before the effective horizon */
9625  if( timepoints[t] <= *hmin )
9626  continue;
9627 
9628  /* ignore all time points after the effective horizon */
9629  if( timepoints[t] >= *hmax )
9630  break;
9631 
9632  /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9633  * can split the cumulative constraint into two cumulative constraints
9634  */
9635  if( loads[t] <= capacity )
9636  {
9637  (*split) = timepoints[t];
9638  break;
9639  }
9640  }
9641  }
9642 
9643  /* free worst case profile */
9644  SCIPprofileFree(&profile);
9645 
9646  return SCIP_OKAY;
9647 }
9648 
9649 /** creates and adds a cumulative constraint */
9650 static
9652  SCIP* scip, /**< SCIP data structure */
9653  const char* name, /**< name of constraint */
9654  int nvars, /**< number of variables (jobs) */
9655  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9656  int* durations, /**< array containing corresponding durations */
9657  int* demands, /**< array containing corresponding demands */
9658  int capacity, /**< available cumulative capacity */
9659  int hmin, /**< left bound of time axis to be considered (including hmin) */
9660  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9661  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9662  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9663  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9664  * Usually set to TRUE. */
9665  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9666  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9667  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9668  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9669  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9670  * Usually set to TRUE. */
9671  SCIP_Bool local, /**< is constraint only valid locally?
9672  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9673  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9674  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9675  * adds coefficients to this constraint. */
9676  SCIP_Bool dynamic, /**< is constraint subject to aging?
9677  * Usually set to FALSE. Set to TRUE for own cuts which
9678  * are seperated as constraints. */
9679  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9680  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9681  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9682  * if it may be moved to a more global node?
9683  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9684  )
9685 {
9686  SCIP_CONS* cons;
9687 
9688  /* creates cumulative constraint and adds it to problem */
9689  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9690  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9691 
9692  /* adjust the effective time horizon of the new constraint */
9693  SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9694  SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9695 
9696  /* add and release new cumulative constraint */
9697  SCIP_CALL( SCIPaddCons(scip, cons) );
9698  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9699 
9700  return SCIP_OKAY;
9701 }
9702 
9703 /** computes the effective horizon and checks if the constraint can be decompsed */
9704 static
9706  SCIP* scip, /**< SCIP data structure */
9707  SCIP_CONS* cons, /**< cumulative constraint */
9708  int* ndelconss, /**< pointer to store the number of deleted constraints */
9709  int* naddconss, /**< pointer to store the number of added constraints */
9710  int* nchgsides /**< pointer to store the number of changed sides */
9711  )
9712 {
9713  SCIP_CONSDATA* consdata;
9714  int hmin;
9715  int hmax;
9716  int split;
9717 
9718  consdata = SCIPconsGetData(cons);
9719  assert(consdata != NULL);
9720 
9721  if( consdata->nvars <= 1 )
9722  return SCIP_OKAY;
9723 
9724  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9725  consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9726 
9727  /* check if this time point improves the effective horizon */
9728  if( consdata->hmin < hmin )
9729  {
9730  SCIPdebugMessage("cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9731 
9732  consdata->hmin = hmin;
9733  (*nchgsides)++;
9734  }
9735 
9736  /* check if this time point improves the effective horizon */
9737  if( consdata->hmax > hmax )
9738  {
9739  SCIPdebugMessage("cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9740  consdata->hmax = hmax;
9741  (*nchgsides)++;
9742  }
9743 
9744  /* check if the constraint is redundant */
9745  if( consdata->hmax <= consdata->hmin )
9746  {
9747  SCIPdebugMessage("constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9748  SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9749 
9750  SCIP_CALL( SCIPdelCons(scip, cons) );
9751  (*ndelconss)++;
9752  }
9753  else if( consdata->hmin < split && split < consdata->hmax )
9754  {
9755  char name[SCIP_MAXSTRLEN];
9756  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9757 
9758  SCIPdebugMessage("split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9759  SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9760 
9761  assert(split < consdata->hmax);
9762 
9763  /* creates cumulative constraint and adds it to problem */
9764  SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9765  consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9768 
9769  /* adjust the effective time horizon of the constraint */
9770  consdata->hmax = split;
9771 
9772  assert(consdata->hmin < consdata->hmax);
9773 
9774  /* for the statistic we count the number of time we decompose a cumulative constraint */
9776  (*naddconss)++;
9777  }
9778 
9779  return SCIP_OKAY;
9780 }
9781 
9782 
9783 /** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9784  *
9785  * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9786  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9787  *
9788  * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9789  * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9790  * down-lock of the corresponding start time variable can be removed.
9791  *
9792  * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9793  * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9794  * negative, than the job can be dual fixed to its earlier start time (est).
9795  *
9796  * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9797  * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9798  * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9799  *
9800  * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9801  * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9802  * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9803  * form variable domain is dual feasible.
9804  *
9805  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9806  * the cumulative condition; The deletion has to be done later.
9807  */
9808 static
9810  SCIP* scip, /**< SCIP data structure */
9811  int nvars, /**< number of start time variables (activities) */
9812  SCIP_VAR** vars, /**< array of start time variables */
9813  int* durations, /**< array of durations */
9814  int hmin, /**< left bound of time axis to be considered (including hmin) */
9815  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9816  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9817  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9818  SCIP_CONS* cons, /**< underlying constraint, or NULL */
9819  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9820  int* nfixedvars, /**< pointer to store the number of fixed variables */
9821  int* nchgsides, /**< pointer to store the number of changed sides */
9822  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9823  )
9824 {
9825  SCIP_Real* downimpllbs;
9826  SCIP_Real* downimplubs;
9827  SCIP_Real* downproplbs;
9828  SCIP_Real* downpropubs;
9829  SCIP_Real* upimpllbs;
9830  SCIP_Real* upimplubs;
9831  SCIP_Real* upproplbs;
9832  SCIP_Real* uppropubs;
9833 
9834  int firstminect;
9835  int secondminect;
9836  int v;
9837 
9838  /* get temporary memory for storing probing results needed for step (4) and (5) */
9839  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9840  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9841  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9842  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9843  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9844  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9845  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9846  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9847 
9848  assert(scip != NULL);
9849  assert(nvars > 1);
9850  assert(cons != NULL);
9851 
9852  SCIPdebugMessage("check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9853 
9854  firstminect = INT_MAX;
9855  secondminect = INT_MAX;
9856 
9857  /* compute the two smallest earlier completion times; which are needed for step (5) */
9858  for( v = 0; v < nvars; ++v )
9859  {
9860  int ect;
9861 
9862  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9863 
9864  if( ect < firstminect )
9865  {
9866  secondminect = firstminect;
9867  firstminect = ect;
9868  }
9869  else if( ect < secondminect )
9870  secondminect = ect;
9871  }
9872 
9873  /* loop over all jobs and check if one of the 5 reductions can be applied */
9874  for( v = 0; v < nvars; ++v )
9875  {
9876  SCIP_VAR* var;
9877  int duration;
9878 
9879  int alternativelb;
9880  int minect;
9881  int est;
9882  int ect;
9883  int lst;
9884  int lct;
9885 
9886  var = vars[v];
9887  assert(var != NULL);
9888 
9889  duration = durations[v];
9890  assert(duration > 0);
9891 
9892  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
9893  * time (lct)
9894  */
9895  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9896  ect = est + duration;
9897  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9898  lct = lst + duration;
9899 
9900  /* compute the earliest completion time of all remaining jobs */
9901  if( ect == firstminect )
9902  minect = secondminect;
9903  else
9904  minect = firstminect;
9905 
9906  /* compute potential alternative lower bound (step (4) and (5)) */
9907  alternativelb = MAX(hmin+1, minect);
9908  alternativelb = MIN(alternativelb, hmax);
9909 
9910  if( lct <= hmin )
9911  {
9912  /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
9913  * cumulative condition
9914  */
9915  SCIPdebugMessage(" variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
9916  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
9917 
9918  /* mark variable to be irrelevant */
9919  irrelevants[v] = TRUE;
9920 
9921  /* for the statistic we count the number of jobs which are irrelevant */
9922  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9923  }
9924  else if( lst <= hmin && SCIPconsIsChecked(cons) )
9925  {
9926  /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
9927  * so the down lock can be omitted
9928  */
9929 
9930  assert(downlocks != NULL);
9931  assert(uplocks != NULL);
9932 
9933  if( !uplocks[v] )
9934  {
9935  /* the variables has no up lock and we can also remove the down lock;
9936  * => lst <= hmin and ect >= hmax
9937  * => remove job and reduce capacity by the demand of that job
9938  *
9939  * We mark the job to be deletable. The removement together with the capacity reducion is done later
9940  */
9941 
9942  SCIPdebugMessage(" variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
9943  SCIPvarGetName(var), ect - duration, lst, duration);
9944 
9945  /* mark variable to be irrelevant */
9946  irrelevants[v] = TRUE;
9947 
9948  /* for the statistic we count the number of jobs which always run during the effective horizon */
9950  }
9951 
9952  if( downlocks[v] )
9953  {
9954  SCIPdebugMessage(" remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
9955  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
9956 
9957  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
9958  downlocks[v] = FALSE;
9959  (*nchgsides)++;
9960 
9961  /* for the statistic we count the number of removed locks */
9963  }
9964  }
9965  else if( ect <= hmin )
9966  {
9967  /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
9968  * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
9969  * removed form the cumulative condition after it was fixed to its earliest start time
9970  */
9971 
9972  /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
9973  * bound;
9974  */
9975  if( downlocks != NULL && SCIPconsIsChecked(cons) )
9976  {
9977  /* fix integer start time variable if possible to it lower bound */
9978  SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
9979  }
9980 
9981  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
9982  {
9983  SCIPdebugMessage(" variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
9984  SCIPvarGetName(var), ect - duration, lst, duration);
9985 
9986  /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
9987  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
9988 
9989  /* mark variable to be irrelevant */
9990  irrelevants[v] = TRUE;
9991 
9992  /* for the statistic we count the number of jobs which are dual fixed */
9994  }
9995  }
9996  else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
9997  {
9998  assert(downlocks != NULL);
9999 
10000  /* check step (4) and (5) */
10001 
10002  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10003  * is in favor of rounding the variable down
10004  */
10005  if( SCIPvarGetNLocksDown(var) == (int)(downlocks[v]) )
10006  {
10007  SCIP_Bool roundable;
10008 
10009  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10010 
10011  if( roundable )
10012  {
10013  if( alternativelb > lst )
10014  {
10015  SCIP_Bool infeasible;
10016  SCIP_Bool fixed;
10017 
10018  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10019  assert(!infeasible);
10020  assert(fixed);
10021 
10022  (*nfixedvars)++;
10023 
10024  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10025  * constraints
10026  */
10028  }
10029  else
10030  {
10031  SCIP_Bool success;
10032 
10033  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10034  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10035  * infeasible we can apply the dual reduction; otherwise we do nothing
10036  */
10037  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10038  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10039  nfixedvars, &success, cutoff) );
10040 
10041  if( success )
10042  {
10044  }
10045  }
10046  }
10047  }
10048  }
10049 
10050  SCIPdebugMessage("********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10051  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10052  }
10053 
10054  /* free temporary memory */
10055  SCIPfreeBufferArray(scip, &uppropubs);
10056  SCIPfreeBufferArray(scip, &upproplbs);
10057  SCIPfreeBufferArray(scip, &upimplubs);
10058  SCIPfreeBufferArray(scip, &upimpllbs);
10059  SCIPfreeBufferArray(scip, &downpropubs);
10060  SCIPfreeBufferArray(scip, &downproplbs);
10061  SCIPfreeBufferArray(scip, &downimplubs);
10062  SCIPfreeBufferArray(scip, &downimpllbs);
10063 
10064  return SCIP_OKAY;
10065 }
10066 
10067 /** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10068  *
10069  * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10070  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10071  *
10072  * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10073  * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10074  * up-lock of the corresponding start time variable can be removed.
10075  *
10076  * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10077  * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10078  * positive, than the job can be dual fixed to its latest start time (lst).
10079  *
10080  * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10081  * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10082  * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10083  * of the corresponding job).
10084 
10085  * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10086  * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10087  * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10088  * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10089  *
10090  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10091  * the cumulative condition; The deletion has to be done later.
10092  */
10093 static
10095  SCIP* scip, /**< SCIP data structure */
10096  int nvars, /**< number of start time variables (activities) */
10097  SCIP_VAR** vars, /**< array of start time variables */
10098  int* durations, /**< array of durations */
10099  int hmin, /**< left bound of time axis to be considered (including hmin) */
10100  int hmax, /**< right bound of time axis to be considered (not including hmax) */
10101  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10102  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10103  SCIP_CONS* cons, /**< underlying constraint, or NULL */
10104  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10105  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10106  int* nchgsides, /**< pointer to store the number of changed sides */
10107  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10108  )
10109 {
10110  SCIP_Real* downimpllbs;
10111  SCIP_Real* downimplubs;
10112  SCIP_Real* downproplbs;
10113  SCIP_Real* downpropubs;
10114  SCIP_Real* upimpllbs;
10115  SCIP_Real* upimplubs;
10116  SCIP_Real* upproplbs;
10117  SCIP_Real* uppropubs;
10118 
10119  int firstmaxlst;
10120  int secondmaxlst;
10121  int v;
10122 
10123  /* get temporary memory for storing probing results needed for step (4) and (5) */
10124  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10125  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10126  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10127  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10128  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10129  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10130  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10131  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10132 
10133  assert(scip != NULL);
10134  assert(nvars > 1);
10135  assert(cons != NULL);
10136 
10137  SCIPdebugMessage("check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10138 
10139  firstmaxlst = INT_MIN;
10140  secondmaxlst = INT_MIN;
10141 
10142  /* compute the two largest latest start times; which are needed for step (5) */
10143  for( v = 0; v < nvars; ++v )
10144  {
10145  int lst;
10146 
10147  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(vars[v]));
10148 
10149  if( lst > firstmaxlst )
10150  {
10151  secondmaxlst = firstmaxlst;
10152  firstmaxlst = lst;
10153  }
10154  else if( lst > secondmaxlst )
10155  secondmaxlst = lst;
10156  }
10157 
10158  /* loop over all jobs and check if one of the 5 reductions can be applied */
10159  for( v = 0; v < nvars; ++v )
10160  {
10161  SCIP_VAR* var;
10162  int duration;
10163 
10164  int alternativeub;
10165  int maxlst;
10166  int est;
10167  int ect;
10168  int lst;
10169 
10170  var = vars[v];
10171  assert(var != NULL);
10172 
10173  duration = durations[v];
10174  assert(duration > 0);
10175 
10176  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10177  * time (lct)
10178  */
10179  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10180  ect = est + duration;
10181  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10182 
10183  /* compute the latest start time of all remaining jobs */
10184  if( lst == firstmaxlst )
10185  maxlst = secondmaxlst;
10186  else
10187  maxlst = firstmaxlst;
10188 
10189  /* compute potential alternative upper bound (step (4) and (5)) */
10190  alternativeub = MIN(hmax - 1, maxlst) - duration;
10191  alternativeub = MAX(alternativeub, hmin);
10192 
10193  if( est >= hmax )
10194  {
10195  /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10196  * cumulative condition
10197  */
10198  SCIPdebugMessage(" variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10199  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10200 
10201  /* mark variable to be irrelevant */
10202  irrelevants[v] = TRUE;
10203 
10204  /* for the statistic we count the number of jobs which are irrelevant */
10205  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10206  }
10207  else if( ect >= hmax && SCIPconsIsChecked(cons) )
10208  {
10209  assert(downlocks != NULL);
10210  assert(uplocks != NULL);
10211 
10212  /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10213  * so the up lock can be omitted
10214  */
10215 
10216  if( !downlocks[v] )
10217  {
10218  /* the variables has no down lock and we can also remove the up lock;
10219  * => lst <= hmin and ect >= hmax
10220  * => remove job and reduce capacity by the demand of that job
10221  */
10222  SCIPdebugMessage(" variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10223  SCIPvarGetName(var), est, lst, duration);
10224 
10225  /* mark variable to be irrelevant */
10226  irrelevants[v] = TRUE;
10227 
10228  /* for the statistic we count the number of jobs which always run during the effective horizon */
10230  }
10231 
10232  if( uplocks[v] )
10233  {
10234  SCIPdebugMessage(" remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10235  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10236 
10237  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10238  uplocks[v] = FALSE;
10239  (*nchgsides)++;
10240 
10241  /* for the statistic we count the number of removed locks */
10243  }
10244  }
10245  else if( lst >= hmax )
10246  {
10247  /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10248  * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10249  * removed form the cumulative condition after it was fixed to its latest start time
10250  */
10251 
10252  /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10253  * bound
10254  */
10255  if( uplocks != NULL && SCIPconsIsChecked(cons) )
10256  {
10257  /* fix integer start time variable if possible to its upper bound */
10258  SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10259  }
10260 
10261  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10262  {
10263  SCIPdebugMessage(" variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10264  SCIPvarGetName(var), est, lst, duration);
10265 
10266  /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10267  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10268 
10269  /* mark variable to be irrelevant */
10270  irrelevants[v] = TRUE;
10271 
10272  /* for the statistic we count the number of jobs which are dual fixed */
10274  }
10275  }
10276  else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10277  {
10278  assert(uplocks != NULL);
10279 
10280  /* check step (4) and (5) */
10281 
10282  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10283  * is in favor of rounding the variable down
10284  */
10285  if( SCIPvarGetNLocksUp(var) == (int)(uplocks[v]) )
10286  {
10287  SCIP_Bool roundable;
10288 
10289  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10290 
10291  if( roundable )
10292  {
10293  if( alternativeub < est )
10294  {
10295  SCIP_Bool infeasible;
10296  SCIP_Bool fixed;
10297 
10298  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10299  assert(!infeasible);
10300  assert(fixed);
10301 
10302  (*nfixedvars)++;
10303 
10304  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10305  * constraints
10306  */
10308  }
10309  else
10310  {
10311  SCIP_Bool success;
10312 
10313  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10314  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10315  * in infeasible we can apply the dual reduction; otherwise we do nothing
10316  */
10317  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10318  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10319  nfixedvars, &success, cutoff) );
10320 
10321  if( success )
10322  {
10324  }
10325  }
10326  }
10327  }
10328  }
10329  }
10330 
10331  /* free temporary memory */
10332  SCIPfreeBufferArray(scip, &uppropubs);
10333  SCIPfreeBufferArray(scip, &upproplbs);
10334  SCIPfreeBufferArray(scip, &upimplubs);
10335  SCIPfreeBufferArray(scip, &upimpllbs);
10336  SCIPfreeBufferArray(scip, &downpropubs);
10337  SCIPfreeBufferArray(scip, &downproplbs);
10338  SCIPfreeBufferArray(scip, &downimplubs);
10339  SCIPfreeBufferArray(scip, &downimpllbs);
10340 
10341  return SCIP_OKAY;
10342 }
10343 
10344 /** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10345 static
10347  SCIP* scip, /**< SCIP data structure */
10348  SCIP_CONS* cons, /**< cumulative constraint */
10349  int* nfixedvars, /**< pointer to store the number of fixed variables */
10350  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10351  int* nchgsides, /**< pointer to store the number of changed sides */
10352  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10353  )
10354 {
10355  SCIP_CONSDATA* consdata;
10356  SCIP_Bool* irrelevants;
10357  int nvars;
10358  int v;
10359 
10360  assert(scip != NULL);
10361  assert(cons != NULL);
10362  assert(!(*cutoff));
10363 
10364  consdata = SCIPconsGetData(cons);
10365  assert(consdata != NULL);
10366 
10367  nvars = consdata->nvars;
10368 
10369  if( nvars <= 1 )
10370  return SCIP_OKAY;
10371 
10372  SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10373  BMSclearMemoryArray(irrelevants, nvars);
10374 
10375  /* presolve constraint form the earlier start time point of view */
10376  SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10377  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10378  irrelevants, nfixedvars, nchgsides, cutoff) );
10379 
10380  /* presolve constraint form the latest completion time point of view */
10381  SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10382  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10383  irrelevants, nfixedvars, nchgsides, cutoff) );
10384 
10385  /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10386  * order to ensure a correct behaviour
10387  */
10388  for( v = nvars-1; v >= 0; --v )
10389  {
10390  if( irrelevants[v] )
10391  {
10392  SCIP_VAR* var;
10393  int ect;
10394  int lst;
10395 
10396  var = consdata->vars[v];
10397  assert(var != NULL);
10398 
10399  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10400  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10401 
10402  /* check if the jobs runs completely during the effective horizon */
10403  if( lst <= consdata->hmin && ect >= consdata->hmax )
10404  {
10405  if( consdata->capacity < consdata->demands[v] )
10406  {
10407  *cutoff = TRUE;
10408  break;
10409  }
10410 
10411  consdata->capacity -= consdata->demands[v];
10412  consdata->varbounds = FALSE;
10413  }
10414 
10415  SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10416  (*nchgcoefs)++;
10417  }
10418  }
10419 
10420  SCIPfreeBufferArray(scip, &irrelevants);
10421 
10422  return SCIP_OKAY;
10423 }
10424 
10425 /** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10426 static
10428  SCIP* scip, /**< SCIP data structure */
10429  SCIP_CONSDATA* consdata, /**< constraint data */
10430  int* startindices, /**< permutation with rspect to the start times */
10431  int curtime, /**< current point in time */
10432  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10433  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10434  SCIP_Longint** demands, /**< pointer to array storing the demands */
10435  int* ndemands /**< pointer to store the number of different demands */
10436  )
10437 {
10438  int startindex;
10439  int ncountedvars;
10440 
10441  assert(demands != NULL);
10442  assert(ndemands != NULL);
10443 
10444  ncountedvars = 0;
10445  startindex = nstarted - 1;
10446 
10447  *ndemands = 0;
10448 
10449  /* search for the (nstarted - nfinished) jobs which are active at curtime */
10450  while( nstarted - nfinished > ncountedvars )
10451  {
10452  SCIP_VAR* var;
10453  int endtime;
10454  int varidx;
10455 
10456  /* collect job information */
10457  varidx = startindices[startindex];
10458  assert(varidx >= 0 && varidx < consdata->nvars);
10459 
10460  var = consdata->vars[varidx];
10461  assert(var != NULL);
10462 
10463  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10464 
10465  /* check the end time of this job is larger than the curtime; in this case the job is still running */
10466  if( endtime > curtime )
10467  {
10468  if( consdata->demands[varidx] < consdata->capacity )
10469  {
10470  (*demands)[*ndemands] = consdata->demands[varidx];
10471  (*ndemands)++;
10472  }
10473  ncountedvars++;
10474  }
10475 
10476  startindex--;
10477  }
10478 
10479  return SCIP_OKAY;
10480 }
10481 
10482 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10483  * constraint
10484  */
10485 static
10487  SCIP* scip, /**< SCIP data structure */
10488  SCIP_CONS* cons, /**< constraint to be checked */
10489  int* startindices, /**< permutation with rspect to the start times */
10490  int curtime, /**< current point in time */
10491  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10492  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10493  int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10494  )
10495 {
10496  SCIP_CONSDATA* consdata;
10497  SCIP_Longint* demands;
10498  SCIP_Real* profits;
10499  int* items;
10500  int ndemands;
10501  SCIP_Bool success;
10502  SCIP_Real solval;
10503  int j;
10504  assert(nstarted > nfinished);
10505 
10506  consdata = SCIPconsGetData(cons);
10507  assert(consdata != NULL);
10508  assert(consdata->nvars > 0);
10509  assert(consdata->capacity > 0);
10510 
10511  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10512  ndemands = 0;
10513 
10514  /* get demand array to initialize knapsack problem */
10515  SCIP_CALL( collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands) );
10516 
10517  /* create array for profits */
10518  SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10519  SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10520  for( j = 0; j < ndemands; ++j )
10521  {
10522  profits[j] = (SCIP_Real) demands[j];
10523  items[j] = j;/* this is only a dummy value*/
10524  }
10525 
10526  /* solve knapsack problem and get maximum capacity usage <= capacity */
10527  SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10528  items, NULL, NULL, NULL, NULL, &solval, &success) );
10529 
10530  assert(SCIPisFeasIntegral(scip, solval));
10531 
10532  /* store result */
10533  *bestcapacity = SCIPconvertRealToInt(scip, solval);
10534 
10535  SCIPfreeBufferArray(scip, &items);
10536  SCIPfreeBufferArray(scip, &profits);
10537  SCIPfreeBufferArray(scip, &demands);
10538 
10539  return SCIP_OKAY;
10540 }
10541 
10542 /** try to tighten the capacity
10543  * -- using DP for knapsack, we find the maximum possible capacity usage
10544  * -- neglects hmin and hmax, such that it is also able to check solutions globally
10545  */
10546 static
10548  SCIP* scip, /**< SCIP data structure */
10549  SCIP_CONS* cons, /**< cumulative constraint */
10550  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10551  int* nchgsides /**< pointer to store the number of changed sides */
10552  )
10553 {
10554  SCIP_CONSDATA* consdata;
10555  int* starttimes; /* stores when each job is starting */
10556  int* endtimes; /* stores when each job ends */
10557  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10558  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10559 
10560  int nvars; /* number of activities for this constraint */
10561  int freecapacity; /* remaining capacity */
10562  int curtime; /* point in time which we are just checking */
10563  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10564 
10565  int bestcapacity;
10566 
10567  int j;
10568 
10569  assert(scip != NULL);
10570  assert(cons != NULL);
10571  assert(nchgsides != NULL);
10572 
10573  consdata = SCIPconsGetData(cons);
10574  assert(consdata != NULL);
10575 
10576  nvars = consdata->nvars;
10577 
10578  /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10579  if( nvars <= 1 || consdata->capacity <= 1 )
10580  return SCIP_OKAY;
10581 
10582  assert(consdata->vars != NULL);
10583 
10584  SCIPdebugMessage("try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10585  SCIPconsGetName(cons), consdata->capacity);
10586 
10587  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10588  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10589  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10590  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10591 
10592  /* create event point arrays */
10593  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10594  starttimes, endtimes, startindices, endindices, FALSE);
10595 
10596  bestcapacity = 1;
10597  endindex = 0;
10598  freecapacity = consdata->capacity;
10599 
10600  /* check each startpoint of a job whether the capacity is kept or not */
10601  for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10602  {
10603  curtime = starttimes[j];
10604  SCIPdebugMessage("look at %d-th job with start %d\n", j, curtime);
10605 
10606  /* remove the capacity requirments for all job which start at the curtime */
10607  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10608 
10609  /* add the capacity requirments for all job which end at the curtime */
10610  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10611 
10612  assert(freecapacity <= consdata->capacity);
10613  assert(endindex <= nvars);
10614 
10615  /* endindex - points to the next job which will finish */
10616  /* j - points to the last job that has been released */
10617 
10618  /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10619  if( freecapacity < 0 )
10620  {
10621  int newcapacity;
10622 
10623  newcapacity = 1;
10624 
10625  /* get best possible upper bound on capacity usage */
10626  SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10627 
10628  /* update bestcapacity */
10629  bestcapacity = MAX(bestcapacity, newcapacity);
10630  SCIPdebugMessage("after highest cap usage: bestcapacity = %d\n", bestcapacity);
10631  }
10632 
10633  /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10634  if( freecapacity > 0 && freecapacity != consdata->capacity )
10635  {
10636  bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10637  SCIPdebugMessage("after peak < cap: bestcapacity = %d\n", bestcapacity);
10638  }
10639 
10640  /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10641  if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10642  {
10643  /* if demands[startindices[j]] == cap then exactly that job is running */
10644  SCIPdebugMessage("--> cannot decrease capacity since sum equals capacity\n");
10645  bestcapacity = consdata->capacity;
10646  break;
10647  }
10648  } /*lint --e{850}*/
10649 
10650  /* free all buffer arrays */
10651  SCIPfreeBufferArray(scip, &endindices);
10652  SCIPfreeBufferArray(scip, &startindices);
10653  SCIPfreeBufferArray(scip, &endtimes);
10654  SCIPfreeBufferArray(scip, &starttimes);
10655 
10656  /* check whether capacity can be tightened and whether demands need to be adjusted */
10657  if( bestcapacity < consdata->capacity )
10658  {
10659  int oldnchgcoefs;
10660 
10661  oldnchgcoefs = *nchgcoefs;
10662 
10663  SCIPdebugMessage("+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10664  SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10665 
10666  for( j = 0; j < nvars; ++j )
10667  {
10668  if( consdata->demands[j] == consdata->capacity )
10669  {
10670  consdata->demands[j] = bestcapacity;
10671  (*nchgcoefs)++;
10672  }
10673  }
10674 
10675  consdata->capacity = bestcapacity;
10676  (*nchgsides)++;
10677 
10678  SCIPdebugPrintf("; changed additionally %d coefficients\n", (*nchgcoefs)-oldnchgcoefs);
10679 
10680  consdata->varbounds = FALSE;
10681  }
10682 
10683  return SCIP_OKAY;
10684 }
10685 
10686 /** tries to change coefficients:
10687  * demand_j < cap && all other parallel jobs in conflict
10688  * ==> set demand_j := cap
10689  */
10690 static
10692  SCIP* scip, /**< SCIP data structure */
10693  SCIP_CONS* cons, /**< cumulative constraint */
10694  int* nchgcoefs /**< pointer to count total number of changed coefficients */
10695  )
10696 {
10697  SCIP_CONSDATA* consdata;
10698  int nvars;
10699  int j;
10700  int oldnchgcoefs;
10701  int mindemand;
10702 
10703  assert(scip != NULL);
10704  assert(cons != NULL);
10705  assert(nchgcoefs != NULL);
10706 
10707  /* get constraint data for some parameter testings only! */
10708  consdata = SCIPconsGetData(cons);
10709  assert(consdata != NULL);
10710 
10711  nvars = consdata->nvars;
10712  oldnchgcoefs = *nchgcoefs;
10713 
10714  if( nvars <= 0 )
10715  return SCIP_OKAY;
10716 
10717  /* PRE1:
10718  * check all jobs j whether: r_j + r_min > capacity holds
10719  * if so: adjust r_j to capacity
10720  */
10721  mindemand = consdata->demands[0];
10722  for( j = 0; j < nvars; ++j )
10723  {
10724  mindemand = MIN(mindemand, consdata->demands[j]);
10725  }
10726 
10727  /*check each job */
10728  for( j = 0; j < nvars; ++j )
10729  {
10730  if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10731  {
10732  SCIPdebugMessage("+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10733  consdata->demands[j], consdata->capacity);
10734  consdata->demands[j] = consdata->capacity;
10735  (*nchgcoefs)++;
10736  }
10737  }
10738 
10739  /* PRE2:
10740  * check for each job (with d_j < cap)
10741  * whether it is disjunctive to all others over the time horizon
10742  */
10743  for( j = 0; j < nvars; ++j )
10744  {
10745  SCIP_Bool chgcoef;
10746  int est_j;
10747  int lct_j;
10748  int i;
10749 
10750  assert(consdata->demands[j] <= consdata->capacity);
10751 
10752  if( consdata->demands[j] == consdata->capacity )
10753  continue;
10754 
10755  chgcoef = TRUE;
10756 
10757  est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10758  lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10759 
10760  for( i = 0; i < nvars; ++i )
10761  {
10762  int est_i;
10763  int lct_i;
10764 
10765  if( i == j )
10766  continue;
10767 
10768  est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10769  lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10770 
10771  if( est_i >= lct_j || est_j >= lct_i )
10772  continue;
10773 
10774  if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10775  {
10776  chgcoef = FALSE;
10777  break;
10778  }
10779  }
10780 
10781  if( chgcoef )
10782  {
10783  SCIPdebugMessage("+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10784  consdata->demands[j], consdata->capacity);
10785  consdata->demands[j] = consdata->capacity;
10786  (*nchgcoefs)++;
10787  }
10788 
10789  }
10790 
10791  if( (*nchgcoefs) > oldnchgcoefs )
10792  {
10793  SCIPdebugMessage("+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10794  (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10795  }
10796 
10797  return SCIP_OKAY;
10798 }
10799 
10800 #if 0
10801 /** try to reformulate constraint by replacing certain jobs */
10802 static
10803 SCIP_RETCODE reformulateCons(
10804  SCIP* scip, /**< SCIP data structure */
10805  SCIP_CONS* cons, /**< cumulative constraint */
10806  int* naggrvars /**< pointer to store the number of aggregated variables */
10807  )
10808 {
10809  SCIP_CONSDATA* consdata;
10810  int hmin;
10811  int hmax;
10812  int nvars;
10813  int v;
10814 
10815  consdata = SCIPconsGetData(cons);
10816  assert(cons != NULL);
10817 
10818  nvars = consdata->nvars;
10819  assert(nvars > 1);
10820 
10821  hmin = consdata->hmin;
10822  hmax = consdata->hmax;
10823  assert(hmin < hmax);
10824 
10825  for( v = 0; v < nvars; ++v )
10826  {
10827  SCIP_VAR* var;
10828  int duration;
10829  int est;
10830  int ect;
10831  int lst;
10832  int lct;
10833 
10834  var = consdata->vars[v];
10835  assert(var != NULL);
10836 
10837  duration = consdata->durations[v];
10838 
10839  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10840  ect = est + duration;
10841  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10842  lct = lst + duration;
10843 
10844  /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10845  assert(lst > hmin || ect < hmax);
10846 
10847  if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10848  {
10849  SCIP_VAR* aggrvar;
10850  char name[SCIP_MAXSTRLEN];
10851  SCIP_Bool infeasible;
10852  SCIP_Bool redundant;
10853  SCIP_Bool aggregated;
10854  int shift;
10855 
10856  shift = est - (hmin - lct + MIN(hmin, ect));
10857  assert(shift > 0);
10858  lst = hmin;
10859  duration = hmin - lct;
10860 
10861  SCIPdebugMessage("replace variable <%s>[%g,%g] by [%d,%d]\n",
10862  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10863 
10864  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10865  SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10867  SCIP_CALL( SCIPaddVar(scip, var) );
10868  SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10869 
10870  assert(!infeasible);
10871  assert(!redundant);
10872  assert(aggregated);
10873 
10874  /* replace variable */
10875  consdata->durations[v] = duration;
10876  consdata->vars[v] = aggrvar;
10877 
10878  /* remove and add locks */
10879  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10880  SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10881 
10882  SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10883 
10884  (*naggrvars)++;
10885  }
10886  }
10887 
10888  return SCIP_OKAY;
10889 }
10890 #endif
10891 
10892 /** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10893 static
10895  SCIP* scip, /**< SCIP data structure */
10896  SCIP_CONS* cons, /**< cumulative constraint */
10897  int* naddconss /**< pointer to store the number of added constraints */
10898  )
10899 {
10900  SCIP_CONSDATA* consdata;
10901  SCIP_VAR** vars;
10902  int* durations;
10903  int* demands;
10904  int capacity;
10905  int halfcapacity;
10906  int mindemand;
10907  int nvars;
10908  int v;
10909 
10910  consdata = SCIPconsGetData(cons);
10911  assert(consdata != NULL);
10912 
10913  capacity = consdata->capacity;
10914 
10915  if( capacity == 1 )
10916  return SCIP_OKAY;
10917 
10918  SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
10919  SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
10920  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10921 
10922  halfcapacity = capacity / 2;
10923  mindemand = consdata->capacity;
10924  nvars = 0;
10925 
10926  /* collect all jobs with demand larger than half of the capacity */
10927  for( v = 0; v < consdata->nvars; ++v )
10928  {
10929  if( consdata->demands[v] > halfcapacity )
10930  {
10931  vars[nvars] = consdata->vars[v];
10932  demands[nvars] = 1;
10933  durations[nvars] = consdata->durations[v];
10934  nvars++;
10935 
10936  mindemand = MIN(mindemand, consdata->demands[v]);
10937  }
10938  }
10939 
10940  if( nvars > 0 )
10941  {
10942  /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
10943  * job is still to large to be scheduled in parallel
10944  */
10945  for( v = 0; v < consdata->nvars; ++v )
10946  {
10947  if( consdata->demands[v] > halfcapacity )
10948  continue;
10949 
10950  if( mindemand + consdata->demands[v] > capacity )
10951  {
10952  demands[nvars] = 1;
10953  durations[nvars] = consdata->durations[v];
10954  vars[nvars] = consdata->vars[v];
10955  nvars++;
10956 
10957  /* @todo create one cumulative constraint and look for another small demand */
10958  break;
10959  }
10960  }
10961 
10962  /* creates cumulative constraint and adds it to problem */
10963  SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
10965  (*naddconss)++;
10966  }
10967 
10968  SCIPfreeBufferArray(scip, &demands);
10969  SCIPfreeBufferArray(scip, &durations);
10970  SCIPfreeBufferArray(scip, &vars);
10971 
10972  return SCIP_OKAY;
10973 }
10974 
10975 /** presolve given constraint */
10976 static
10978  SCIP* scip, /**< SCIP data structure */
10979  SCIP_CONS* cons, /**< cumulative constraint */
10980  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
10981  SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
10982  int* nfixedvars, /**< pointer to store the number of fixed variables */
10983 #if 0
10984  int* naggrvars, /**< pointer to counter which is increased by the number of deduced variable aggregations */
10985 #endif
10986  int* nchgbds, /**< pointer to store the number of changed bounds */
10987  int* ndelconss, /**< pointer to store the number of deleted constraints */
10988  int* naddconss, /**< pointer to store the number of added constraints */
10989  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10990  int* nchgsides, /**< pointer to store the number of changed sides */
10991  SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
10992  SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
10993  )
10994 {
10995  assert(!SCIPconsIsDeleted(cons));
10996 
10997  /* only perform dual reductions on model constraints */
10998  if( conshdlrdata->dualpresolve && SCIPallowDualReds(scip) )
10999  {
11000  /* computes the effective horizon and checks if the constraint can be decomposed */
11001  SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11002 
11003  if( SCIPconsIsDeleted(cons) )
11004  return SCIP_OKAY;
11005 
11006  /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11007  * fixings (dual reductions)
11008  */
11009  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11010  {
11011  SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11012 
11013  if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11014  return SCIP_OKAY;
11015  }
11016 
11017  SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11018 
11019  if( *cutoff || SCIPconsIsDeleted(cons) )
11020  return SCIP_OKAY;
11021  }
11022 
11023  /* remove jobs which have a demand larger than the capacity */
11024  SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11025  assert((*cutoff) || checkDemands(scip, cons));
11026 
11027  if( *cutoff )
11028  return SCIP_OKAY;
11029 
11030  if( conshdlrdata->normalize )
11031  {
11032  /* divide demands by their greatest common divisor */
11033  SCIP_CALL( normalizeDemands(scip, cons, nchgcoefs, nchgsides) );
11034  }
11035 
11036  /* delete constraint with one job */
11037  SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11038 
11039  if( *cutoff || SCIPconsIsDeleted(cons) )
11040  return SCIP_OKAY;
11041 
11042  if( conshdlrdata->coeftightening )
11043  {
11044  /* try to tighten the capacity */
11045  SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11046 
11047  /* try to tighten the coefficients */
11048  SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11049  }
11050 
11051  assert(checkDemands(scip, cons) || *cutoff);
11052 
11053 #if 0
11054  SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11055 #endif
11056 
11057  return SCIP_OKAY;
11058 }
11059 
11060 /**@name TClique Graph callbacks
11061  *
11062  * @{
11063  */
11064 
11065 /** tclique graph data */
11066 struct TCLIQUE_Graph
11067 {
11068  SCIP_VAR** vars; /**< start time variables each of them is a node */
11069  SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11070  SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11071  SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11072  TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11073  int* ninarcs; /**< number if in arcs for the precedence graph */
11074  int* noutarcs; /**< number if out arcs for the precedence graph */
11075  int* durations; /**< for each node the duration of the corresponding job */
11076  int nnodes; /**< number of nodes */
11077  int size; /**< size of the array */
11078 };
11079 
11080 /** gets number of nodes in the graph */
11081 static
11082 TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11084  assert(tcliquegraph != NULL);
11085 
11086  return tcliquegraph->nnodes;
11087 }
11088 
11089 /** gets weight of nodes in the graph */
11090 static
11091 TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11093  assert(tcliquegraph != NULL);
11094 
11095  return tcliquegraph->weights;
11096 }
11097 
11098 /** returns, whether the edge (node1, node2) is in the graph */
11099 static
11100 TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11102  assert(tcliquegraph != NULL);
11103  assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11104  assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11105 
11106  /* check if an arc exits in the precedence graph */
11107  if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11108  return TRUE;
11109 
11110  /* check if an edge exits in the non-overlapping graph */
11111  if( tcliquegraph->demandmatrix[node1][node2] )
11112  return TRUE;
11113 
11114  return FALSE;
11115 }
11116 
11117 /** selects all nodes from a given set of nodes which are adjacent to a given node
11118  * and returns the number of selected nodes
11119  */
11120 static
11121 TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11123  int nadjnodes;
11124  int i;
11125 
11126  assert(tcliquegraph != NULL);
11127  assert(0 <= node && node < tcliquegraph->nnodes);
11128  assert(nnodes == 0 || nodes != NULL);
11129  assert(adjnodes != NULL);
11130 
11131  nadjnodes = 0;
11132 
11133  for( i = 0; i < nnodes; i++ )
11134  {
11135  /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11136  assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11137  assert(i == 0 || nodes[i-1] < nodes[i]);
11138 
11139  /* check if an edge exists */
11140  if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11141  {
11142  /* current node is adjacent to given node */
11143  adjnodes[nadjnodes] = nodes[i];
11144  nadjnodes++;
11145  }
11146  }
11147 
11148  return nadjnodes;
11149 }
11150 
11151 /** generates cuts using a clique found by algorithm for maximum weight clique
11152  * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11153  */
11154 static
11155 TCLIQUE_NEWSOL(tcliqueNewsolClique)
11156 { /*lint --e{715}*/
11157  SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11158 }
11159 
11160 /** print the tclique graph */
11161 #if 0
11162 static
11163 void tcliquePrint(
11164  SCIP* scip, /**< SCIP data structure */
11165  TCLIQUE_GRAPH* tcliquegraph /**< tclique graph */
11166  )
11167 {
11168  int nnodes;
11169  int i;
11170  int j;
11171 
11172  nnodes = tcliquegraph->nnodes;
11173 
11174  for( i = 0; i < nnodes; ++i )
11175  {
11176  for( j = 0; j < nnodes; ++j )
11177  {
11178  SCIPinfoMessage(scip, NULL, "(%d/%d) ", tcliquegraph->precedencematrix[i][j], tcliquegraph->demandmatrix[i][j]);
11179  }
11180  SCIPinfoMessage(scip, NULL, "\n");
11181  }
11182 }
11183 #endif
11184 
11185 /** @} */
11186 
11187 /** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11188  * job corresponding to variable bound variable (vlbvar)
11189  *
11190  * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11191  */
11192 static
11194  SCIP* scip, /**< SCIP data structure */
11195  SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11196  SCIP_Real vlbcoef, /**< variable bound coefficient */
11197  SCIP_Real vlbconst, /**< variable bound constant */
11198  int duration /**< duration of the variable bound variable */
11199  )
11200 {
11201  if( SCIPisEQ(scip, vlbcoef, 1.0) )
11202  {
11203  if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11204  {
11205  /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11206  return TRUE;
11207  }
11208  }
11209  else
11210  {
11211  SCIP_Real bound;
11212 
11213  bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11214 
11215  if( SCIPisLT(scip, vlbcoef, 1.0) )
11216  {
11217  SCIP_Real ub;
11218 
11219  ub = SCIPvarGetUbLocal(vlbvar);
11220 
11221  /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11222  if( SCIPisLE(scip, ub, bound) )
11223  return TRUE;
11224  }
11225  else
11226  {
11227  SCIP_Real lb;
11228 
11229  assert(SCIPisGT(scip, vlbcoef, 1.0));
11230 
11231  lb = SCIPvarGetLbLocal(vlbvar);
11232 
11233  /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11234  if( SCIPisGE(scip, lb, bound) )
11235  return TRUE;
11236  }
11237  }
11238 
11239  return FALSE;
11240 }
11241 
11242 /** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11243  * job corresponding to variable which is bounded (var)
11244  *
11245  * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11246  */
11247 static
11249  SCIP* scip, /**< SCIP data structure */
11250  SCIP_VAR* var, /**< variable which is bound from above */
11251  SCIP_Real vubcoef, /**< variable bound coefficient */
11252  SCIP_Real vubconst, /**< variable bound constant */
11253  int duration /**< duration of the variable which is bounded from above */
11254  )
11255 {
11256  SCIP_Real vlbcoef;
11257  SCIP_Real vlbconst;
11258 
11259  /* convert the variable upper bound into an variable lower bound */
11260  vlbcoef = 1.0 / vubcoef;
11261  vlbconst = -vubconst / vubcoef;
11262 
11263  return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11264 }
11265 
11266 /** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11267  * others an index larger than the number if active variables
11268  */
11269 static
11271  SCIP* scip, /**< SCIP data structure */
11272  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11273  SCIP_VAR* var, /**< variable for which we want the index */
11274  int* idx /**< pointer to store the index */
11275  )
11276 {
11277  (*idx) = SCIPvarGetProbindex(var);
11278 
11279  if( (*idx) == -1 )
11280  {
11281  if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11282  {
11283  (*idx) = (int)(size_t) SCIPhashmapGetImage(tcliquegraph->varmap, (void*)var);
11284  }
11285  else
11286  {
11287  int pos;
11288  int v;
11289 
11290  /**@todo we might want to add the aggregation path to graph */
11291 
11292  /* check if we have to realloc memory */
11293  if( tcliquegraph->size == tcliquegraph->nnodes )
11294  {
11295  int size;
11296 
11297  size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11298  tcliquegraph->size = size;
11299 
11300  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11301  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11302  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11303  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11304  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11305 
11306  for( v = 0; v < tcliquegraph->nnodes; ++v )
11307  {
11308  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11309  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11310  }
11311  }
11312  assert(tcliquegraph->nnodes < tcliquegraph->size);
11313 
11314  pos = tcliquegraph->nnodes;
11315  assert(pos >= 0);
11316 
11317  tcliquegraph->durations[pos] = 0;
11318  tcliquegraph->weights[pos] = 0;
11319  tcliquegraph->vars[pos] = var;
11320 
11321  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11322  BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11323 
11324  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11325  BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11326 
11327  SCIP_CALL( SCIPhashmapInsert(tcliquegraph->varmap, (void*)var, (void*)(size_t)(pos)) );
11328 
11329  tcliquegraph->nnodes++;
11330 
11331  for( v = 0; v < tcliquegraph->nnodes; ++v )
11332  {
11333  tcliquegraph->precedencematrix[v][pos] = 0;
11334  tcliquegraph->demandmatrix[v][pos] = 0;
11335  }
11336 
11337  (*idx) = tcliquegraph->nnodes;
11338  }
11339  }
11340  else
11341  {
11342  assert(*idx == (int)(size_t)SCIPhashmapGetImage(tcliquegraph->varmap, (void*)var));
11343  }
11344 
11345  assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11346 
11347  return SCIP_OKAY;
11348 }
11349 
11350 /** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11351  *
11352  * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11353  * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11354  *
11355  * (i) b = 1 and c >= d
11356  * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11357  * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11358  *
11359  */
11360 static
11362  SCIP* scip, /**< SCIP data structure */
11363  TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11364  )
11365 {
11366  SCIP_VAR** vars;
11367  int nvars;
11368  int v;
11369 
11370  vars = SCIPgetVars(scip);
11371  nvars = SCIPgetNVars(scip);
11372 
11373  /* try to project each arc of the variable bound graph to precedence condition */
11374  for( v = 0; v < nvars; ++v )
11375  {
11376  SCIP_VAR** vbdvars;
11377  SCIP_VAR* var;
11378  SCIP_Real* vbdcoefs;
11379  SCIP_Real* vbdconsts;
11380  int nvbdvars;
11381  int idx1;
11382  int b;
11383 
11384  var = vars[v];
11385  assert(var != NULL);
11386 
11387  SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11388  assert(idx1 >= 0);
11389 
11390  if( tcliquegraph->durations[idx1] == 0 )
11391  continue;
11392 
11393  vbdvars = SCIPvarGetVlbVars(var);
11394  vbdcoefs = SCIPvarGetVlbCoefs(var);
11395  vbdconsts = SCIPvarGetVlbConstants(var);
11396  nvbdvars = SCIPvarGetNVlbs(var);
11397 
11398  for( b = 0; b < nvbdvars; ++b )
11399  {
11400  int idx2;
11401 
11402  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11403  assert(idx2 >= 0);
11404 
11405  if( tcliquegraph->durations[idx2] == 0 )
11406  continue;
11407 
11408  if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11409  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11410  }
11411 
11412  vbdvars = SCIPvarGetVubVars(var);
11413  vbdcoefs = SCIPvarGetVubCoefs(var);
11414  vbdconsts = SCIPvarGetVubConstants(var);
11415  nvbdvars = SCIPvarGetNVubs(var);
11416 
11417  for( b = 0; b < nvbdvars; ++b )
11418  {
11419  int idx2;
11420 
11421  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11422  assert(idx2 >= 0);
11423 
11424  if( tcliquegraph->durations[idx2] == 0 )
11425  continue;
11426 
11427  if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11428  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11429  }
11430 
11431  for( b = v+1; b < nvars; ++b )
11432  {
11433  int idx2;
11434 
11435  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11436  assert(idx2 >= 0);
11437 
11438  if( tcliquegraph->durations[idx2] == 0 )
11439  continue;
11440 
11441  /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11442  if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11443  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11444 
11445  /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11446  if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11447  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11448  }
11449  }
11450 
11451  return SCIP_OKAY;
11452 }
11453 
11454 /** compute the transitive closer of the given graph and the number of in and out arcs */
11455 static
11456 void transitiveClosure(
11457  SCIP_Bool** adjmatrix, /**< adjacent matrix */
11458  int* ninarcs, /**< array to store the number of in arcs */
11459  int* noutarcs, /**< array to store the number of out arcs */
11460  int nnodes /**< number if nodes */
11461  )
11462 {
11463  int i;
11464  int j;
11465  int k;
11466 
11467  for( i = 0; i < nnodes; ++i )
11468  {
11469  for( j = 0; j < nnodes; ++j )
11470  {
11471  if( adjmatrix[i][j] )
11472  {
11473  ninarcs[j]++;
11474  noutarcs[i]++;
11475 
11476  for( k = 0; k < nnodes; ++k )
11477  {
11478  if( adjmatrix[j][k] )
11479  adjmatrix[i][k] = TRUE;
11480  }
11481  }
11482  }
11483  }
11484 }
11485 
11486 /** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11487 static
11489  SCIP* scip, /**< SCIP data structure */
11490  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11491  SCIP_CONS** conss, /**< array of cumulative constraints */
11492  int nconss /**< number of cumulative constraints */
11493  )
11494 {
11495  int c;
11496 
11497  /* use the cumulative constraints to initialize the none overlapping graph */
11498  for( c = 0; c < nconss; ++c )
11499  {
11500  SCIP_CONSDATA* consdata;
11501  SCIP_VAR** vars;
11502  int* demands;
11503  int capacity;
11504  int nvars;
11505  int i;
11506 
11507  consdata = SCIPconsGetData(conss[c]);
11508  assert(consdata != NULL);
11509 
11510  vars = consdata->vars;
11511  demands = consdata->demands;
11512 
11513  nvars = consdata->nvars;
11514  capacity = consdata->capacity;
11515 
11516  SCIPdebugMessage("constraint <%s>\n", SCIPconsGetName(conss[c]));
11517 
11518  /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11519  for( i = 0; i < nvars; ++i )
11520  {
11521  int idx1;
11522  int j;
11523 
11524  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11525  assert(idx1 >= 0);
11526 
11527  if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11528  continue;
11529 
11530  for( j = i+1; j < nvars; ++j )
11531  {
11532  assert(consdata->durations[j] > 0);
11533 
11534  if( demands[i] + demands[j] > capacity )
11535  {
11536  int idx2;
11537  int est1;
11538  int est2;
11539  int lct1;
11540  int lct2;
11541 
11542  /* check if the effective horizon is large enough */
11543  est1 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[i]));
11544  est2 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[j]));
11545 
11546  /* at least one of the jobs needs to start at hmin or later */
11547  if( est1 < consdata->hmin && est2 < consdata->hmin )
11548  continue;
11549 
11550  lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11551  lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11552 
11553  /* at least one of the jobs needs to finish not later then hmin */
11554  if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11555  continue;
11556 
11557  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11558  assert(idx2 >= 0);
11559  assert(idx1 != idx2);
11560 
11561  if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11562  continue;
11563 
11564  SCIPdebugMessage(" *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11565 
11566  assert(tcliquegraph->durations[idx1] > 0);
11567  assert(tcliquegraph->durations[idx2] > 0);
11568 
11569  tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11570  tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11571 
11572  }
11573  }
11574  }
11575  }
11576 
11577  return SCIP_OKAY;
11578 }
11579 
11580 /** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11581  * of jobs cannot run in parallel
11582  */
11583 static
11585  SCIP* scip, /**< SCIP data structure */
11586  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11587  SCIP_CONS** conss, /**< array of cumulative constraints */
11588  int nconss /**< number of cumulative constraints */
11589  )
11590 {
11591  assert(scip != NULL);
11592  assert(tcliquegraph != NULL);
11593 
11594  /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11595  SCIP_CALL( projectVbd(scip, tcliquegraph) );
11596 
11597  /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11598  transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11599 
11600  /* constraints non-overlapping graph */
11601  SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11602 
11603  return SCIP_OKAY;
11604 }
11605 
11606 /** create cumulative constraint from conflict set */
11607 static
11609  SCIP* scip, /**< SCIP data structure */
11610  const char* name, /**< constraint name */
11611  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11612  int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11613  int ncliquenodes /**< number of nodes in the clique */
11614  )
11615 {
11616  SCIP_CONS* cons;
11617  SCIP_VAR** vars;
11618  int* durations;
11619  int* demands;
11620  int v;
11621 
11622  SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11623  SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11624  SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11625 
11626  SCIPsortInt(cliquenodes, ncliquenodes);
11627 
11628  /* collect variables, durations, and demands */
11629  for( v = 0; v < ncliquenodes; ++v )
11630  {
11631  durations[v] = tcliquegraph->durations[cliquenodes[v]];
11632  assert(durations[v] > 0);
11633  demands[v] = 1;
11634  vars[v] = tcliquegraph->vars[cliquenodes[v]];
11635  }
11636 
11637  /* create (unary) cumulative constraint */
11638  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11640 
11641  SCIP_CALL( SCIPaddCons(scip, cons) );
11642  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11643 
11644  /* free buffers */
11645  SCIPfreeBufferArray(scip, &demands);
11646  SCIPfreeBufferArray(scip, &durations);
11647  SCIPfreeBufferArray(scip, &vars);
11648 
11649  return SCIP_OKAY;
11650 }
11651 
11652 /** search for cumulative constrainst */
11653 static
11655  SCIP* scip, /**< SCIP data structure */
11656  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11657  int* naddconss /**< pointer to store the number of added constraints */
11658  )
11659 {
11660  TCLIQUE_STATUS tcliquestatus;
11661  SCIP_Bool* precedencerow;
11662  SCIP_Bool* precedencecol;
11663  SCIP_Bool* demandrow;
11664  SCIP_Bool* demandcol;
11665  SCIP_HASHTABLE* covered;
11666  int* cliquenodes;
11667  int ncliquenodes;
11668  int cliqueweight;
11669  int ntreenodes;
11670  int nnodes;
11671  int nconss;
11672  int v;
11673 
11674  nnodes = tcliquegraph->nnodes;
11675  nconss = 0;
11676 
11677  /* initialize the weight of each job with its duration */
11678  for( v = 0; v < nnodes; ++v )
11679  {
11680  tcliquegraph->weights[v] = tcliquegraph->durations[v];
11681  }
11682 
11683  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11684  SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11685  SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11686  SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11687  SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11688 
11689  /* create a hash table to store all start time variables which are already covered by at least one clique */
11691  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11692 
11693  /* for each variables/job we are ... */
11694  for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11695  {
11696  char name[SCIP_MAXSTRLEN];
11697  int c;
11698 
11699  /* jobs with zero durations are skipped */
11700  if( tcliquegraph->durations[v] == 0 )
11701  continue;
11702 
11703  /* check if the start time variable is already covered by at least one clique */
11704  if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11705  continue;
11706 
11707  SCIPdebugMessage("********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11708 
11709  /* temporarily remove the connection via the precedence graph */
11710  for( c = 0; c < nnodes; ++c )
11711  {
11712  precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11713  precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11714 
11715  demandrow[c] = tcliquegraph->demandmatrix[v][c];
11716  demandcol[c] = tcliquegraph->demandmatrix[c][v];
11717 
11718 #if 0
11719  if( precedencerow[c] || precedencecol[c] )
11720  {
11721  tcliquegraph->demandmatrix[v][c] = FALSE;
11722  tcliquegraph->demandmatrix[c][v] = FALSE;
11723  }
11724 #endif
11725 
11726  tcliquegraph->precedencematrix[c][v] = FALSE;
11727  tcliquegraph->precedencematrix[v][c] = FALSE;
11728  }
11729 
11730  /* find (heuristically) maximum cliques which includes node v */
11731  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11732  tcliquegraph, tcliqueNewsolClique, NULL,
11733  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11734  10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11735 
11736  SCIPdebugMessage("tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11737 
11738  if( ncliquenodes == 1 )
11739  continue;
11740 
11741  /* construct constraint name */
11742  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11743 
11744  SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11745  nconss++;
11746 
11747  /* all start time variable to covered hash table */
11748  for( c = 0; c < ncliquenodes; ++c )
11749  {
11750  SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11751  }
11752 
11753  /* copy the precedence relations back */
11754  for( c = 0; c < nnodes; ++c )
11755  {
11756  tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11757  tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11758 
11759  tcliquegraph->demandmatrix[v][c] = demandrow[c];
11760  tcliquegraph->demandmatrix[c][v] = demandcol[c];
11761  }
11762  }
11763 
11764  SCIPhashtableFree(&covered);
11765 
11766  SCIPfreeBufferArray(scip, &demandcol);
11767  SCIPfreeBufferArray(scip, &demandrow);
11768  SCIPfreeBufferArray(scip, &precedencecol);
11769  SCIPfreeBufferArray(scip, &precedencerow);
11770  SCIPfreeBufferArray(scip, &cliquenodes);
11771 
11772  (*naddconss) += nconss;
11773 
11774  /* for the statistic we count the number added disjunctive constraints */
11775  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11776 
11777  return SCIP_OKAY;
11778 }
11779 
11780 /** create precedence constraint (as variable bound constraint */
11781 static
11783  SCIP* scip, /**< SCIP data structure */
11784  const char* name, /**< constraint name */
11785  SCIP_VAR* var, /**< variable x that has variable bound */
11786  SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11787  int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11788  )
11789 {
11790  SCIP_CONS* cons;
11791 
11792  /* create variable bound constraint */
11793  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11795 
11796  SCIPdebugPrintCons(scip, cons, NULL);
11797 
11798  /* add constraint to problem and release it */
11799  SCIP_CALL( SCIPaddCons(scip, cons) );
11800  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11801 
11802  return SCIP_OKAY;
11803 }
11804 
11805 /** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11806 static
11808  SCIP* scip, /**< SCIP data structure */
11809  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11810  int source, /**< index of the source node */
11811  int sink, /**< index of the sink node */
11812  int* naddconss /**< pointer to store the number of added constraints */
11813  )
11814 {
11815  TCLIQUE_WEIGHT cliqueweight;
11816  TCLIQUE_STATUS tcliquestatus;
11817  SCIP_VAR** vars;
11818  int* cliquenodes;
11819  int nnodes;
11820  int lct;
11821  int est;
11822  int i;
11823 
11824  int ntreenodes;
11825  int ncliquenodes;
11826 
11827  /* check if source and sink are connencted */
11828  if( !tcliquegraph->precedencematrix[source][sink] )
11829  return SCIP_OKAY;
11830 
11831  nnodes = tcliquegraph->nnodes;
11832  vars = tcliquegraph->vars;
11833 
11834  /* reset the weights to zero */
11835  BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11836 
11837  /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11838  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11839  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[sink]));
11840 
11841  /* weight all jobs which run for sure between source and sink with their duration */
11842  for( i = 0; i < nnodes; ++i )
11843  {
11844  SCIP_VAR* var;
11845  int duration;
11846 
11847  var = vars[i];
11848  assert(var != NULL);
11849 
11850  duration = tcliquegraph->durations[i];
11851 
11852  if( i == source || i == sink )
11853  {
11854  /* source and sink are not weighted */
11855  tcliquegraph->weights[i] = 0;
11856  }
11857  else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11858  {
11859  /* job i runs after source and before sink */
11860  tcliquegraph->weights[i] = duration;
11861  }
11862  else if( lct <= SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var))
11863  && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11864  {
11865  /* job i run in between due the bounds of the start time variables */
11866  tcliquegraph->weights[i] = duration;
11867  }
11868  else
11869  tcliquegraph->weights[i] = 0;
11870  }
11871 
11872  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11873 
11874  /* find (heuristically) maximum cliques */
11875  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11876  tcliquegraph, tcliqueNewsolClique, NULL,
11877  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11878  10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11879 
11880  if( ncliquenodes > 1 )
11881  {
11882  char name[SCIP_MAXSTRLEN];
11883  int distance;
11884 
11885  /* construct constraint name */
11886  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11887 
11888  /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11889  * duration of the source job
11890  */
11891  distance = cliqueweight + tcliquegraph->durations[source];
11892 
11893  SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11894  (*naddconss)++;
11895  }
11896 
11897  SCIPfreeBufferArray(scip, &cliquenodes);
11898 
11899  return SCIP_OKAY;
11900 }
11901 
11902 /** search for precedence constraints
11903  *
11904  * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
11905  * corresponding two jobs
11906  */
11907 static
11909  SCIP* scip, /**< SCIP data structure */
11910  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11911  int* naddconss /**< pointer to store the number of added constraints */
11912  )
11913 {
11914  int* sources;
11915  int* sinks;
11916  int nconss;
11917  int nnodes;
11918  int nsources;
11919  int nsinks;
11920  int i;
11921 
11922  nnodes = tcliquegraph->nnodes;
11923  nconss = 0;
11924 
11925  nsources = 0;
11926  nsinks = 0;
11927 
11928  SCIP_CALL( SCIPallocBufferArray(scip, &sources, nnodes) );
11929  SCIP_CALL( SCIPallocBufferArray(scip, &sinks, nnodes) );
11930 
11931  /* first collect all sources and sinks */
11932  for( i = 0; i < nnodes; ++i )
11933  {
11934  if( tcliquegraph->ninarcs[i] == 0 )
11935  {
11936  sources[nsources] = i;
11937  nsources++;
11938  }
11939 
11940  if( tcliquegraph->ninarcs[i] == 0 )
11941  {
11942  sinks[nsinks] = i;
11943  nsinks++;
11944  }
11945  }
11946 
11947  /* compute for each node a minimum distance to each sources and each sink */
11948  for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
11949  {
11950  int j;
11951 
11952  for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
11953  {
11954  SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
11955  }
11956 
11957  for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
11958  {
11959  SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
11960  }
11961  }
11962 
11963  (*naddconss) += nconss;
11964 
11965  /* for the statistic we count the number added variable constraints */
11966  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
11967 
11968  SCIPfreeBufferArray(scip, &sinks);
11969  SCIPfreeBufferArray(scip, &sources);
11970 
11971  return SCIP_OKAY;
11972 }
11973 
11974 /** initialize the assumed durations for each variable */
11975 static
11977  SCIP* scip, /**< SCIP data structure */
11978  TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
11979  SCIP_CONS** conss, /**< cumulative constraints */
11980  int nconss /**< number of cumulative constraints */
11981  )
11982 {
11983  int c;
11984 
11985  /* use the cumulative structure to define the duration we are using for each job */
11986  for( c = 0; c < nconss; ++c )
11987  {
11988  SCIP_CONSDATA* consdata;
11989  SCIP_VAR** vars;
11990  int nvars;
11991  int v;
11992 
11993  consdata = SCIPconsGetData(conss[c]);
11994  assert(consdata != NULL);
11995 
11996  vars = consdata->vars;
11997  nvars = consdata->nvars;
11998 
11999  for( v = 0; v < nvars; ++v )
12000  {
12001  int idx;
12002 
12003  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12004  assert(idx >= 0);
12005 
12006  /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12007  * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12008  * general this is not the case. Therefore, the question would be which duration should be used?
12009  */
12010  tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12011  assert(tcliquegraph->durations[idx] > 0);
12012  }
12013  }
12014 
12015  return SCIP_OKAY;
12016 }
12017 
12018 /** create tclique graph */
12019 static
12021  SCIP* scip, /**< SCIP data structure */
12022  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12023  )
12024 {
12025  SCIP_VAR** vars;
12026  SCIP_HASHMAP* varmap;
12027  SCIP_Bool** precedencematrix;
12028  SCIP_Bool** demandmatrix;
12029  int* ninarcs;
12030  int* noutarcs;
12031  int* durations;
12032  int* weights;
12033  int nvars;
12034  int v;
12035 
12036  vars = SCIPgetVars(scip);
12037  nvars = SCIPgetNVars(scip);
12038 
12039  /* allocate memory for the tclique graph data structure */
12040  SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12041 
12042  /* create the variable mapping hash map */
12043  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), SCIPcalcHashtableSize(5 * nvars)) );
12044 
12045  /* each active variables get a node in the graph */
12046  SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12047 
12048  /* allocate memory for the projected variables bound graph and the none overlapping graph */
12049  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12050  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12051 
12052  /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12053  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12054  BMSclearMemoryArray(weights, nvars);
12055 
12056  /* array to store the number of in arc of the precedence graph */
12057  SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12058  BMSclearMemoryArray(ninarcs, nvars);
12059 
12060  /* array to store the number of out arc of the precedence graph */
12061  SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12062  BMSclearMemoryArray(noutarcs, nvars);
12063 
12064  /* array to store the used duration for each node */
12065  SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12066  BMSclearMemoryArray(durations, nvars);
12067 
12068  for( v = 0; v < nvars; ++v )
12069  {
12070  SCIP_VAR* var;
12071 
12072  var = vars[v];
12073  assert(var != NULL);
12074 
12075  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12076  BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12077 
12078  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12079  BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12080 
12081  /* insert all active variables into the garph */
12082  assert(SCIPvarGetProbindex(var) == v);
12083  SCIP_CALL( SCIPhashmapInsert(varmap, (void*)var, (void*)(size_t)v) ); /*lint !e571*/
12084  }
12085 
12086  (*tcliquegraph)->nnodes = nvars;
12087  (*tcliquegraph)->varmap = varmap;
12088  (*tcliquegraph)->precedencematrix = precedencematrix;
12089  (*tcliquegraph)->demandmatrix = demandmatrix;
12090  (*tcliquegraph)->weights = weights;
12091  (*tcliquegraph)->ninarcs = ninarcs;
12092  (*tcliquegraph)->noutarcs = noutarcs;
12093  (*tcliquegraph)->durations = durations;
12094  (*tcliquegraph)->size = nvars;
12095 
12096  return SCIP_OKAY;
12097 }
12098 
12099 /** frees the tclique graph */
12100 static
12101 void freeTcliqueGraph(
12102  SCIP* scip, /**< SCIP data structure */
12103  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12104  )
12105 {
12106  int v;
12107 
12108  for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12109  {
12110  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12111  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12112  }
12113 
12114  SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12115  SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12116  SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12117  SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12118  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12119  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12120  SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12121  SCIPhashmapFree(&(*tcliquegraph)->varmap);
12122 
12123  SCIPfreeBuffer(scip, tcliquegraph);
12124 }
12125 
12126 /** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12127  * constrains (disjunctive constraint)
12128  */
12129 static
12131  SCIP* scip, /**< SCIP data structure */
12132  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12133  SCIP_CONS** conss, /**< array of cumulative constraints */
12134  int nconss, /**< number of cumulative constraints */
12135  int* naddconss /**< pointer to store the number of added constraints */
12136  )
12137 {
12138  TCLIQUE_GRAPH* tcliquegraph;
12139 
12140  /* create tclique graph */
12141  SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12142 
12143  /* define for each job a duration */
12144  SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12145 
12146  /* constuct incompatibility graph */
12147  SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12148 
12149  /* search for new precedence constraints */
12150  if( conshdlrdata->detectvarbounds )
12151  {
12152  SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12153  }
12154 
12155  /* search for new cumulative constraints */
12156  if( conshdlrdata->detectdisjunctive )
12157  {
12158  SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12159  }
12160 
12161  /* free tclique graph data structure */
12162  freeTcliqueGraph(scip, &tcliquegraph);
12163 
12164  return SCIP_OKAY;
12165 }
12166 
12167 /** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12168 static
12170  SCIP_CONSDATA* consdata /**< cumulative constraint data */
12171  )
12172 {
12173  SCIP_VAR** vars;
12174  int nvars;
12175  int v;
12176 
12177  if( consdata->validsignature )
12178  return;
12179 
12180  vars = consdata->vars;
12181  nvars = consdata->nvars;
12182 
12183  for( v = 0; v < nvars; ++v )
12184  {
12185  consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12186  }
12187 
12188  consdata->validsignature = TRUE;
12189 }
12190 
12191 /** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12192 static
12193 SCIP_DECL_SORTINDCOMP(consdataCompVar)
12194 { /*lint --e{715}*/
12195  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12196 
12197  assert(consdata != NULL);
12198  assert(0 <= ind1 && ind1 < consdata->nvars);
12199  assert(0 <= ind2 && ind2 < consdata->nvars);
12200 
12201  return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12202 }
12203 
12204 /** run a pairwise comparison */
12205 static
12207  SCIP* scip, /**< SCIP data structure */
12208  SCIP_CONS** conss, /**< array of cumulative constraints */
12209  int nconss, /**< number of cumulative constraints */
12210  int* ndelconss /**< pointer to store the number of deletedconstraints */
12211  )
12212 {
12213  int i;
12214  int j;
12215 
12216  for( i = 0; i < nconss; ++i )
12217  {
12218  SCIP_CONSDATA* consdata0;
12219  SCIP_CONS* cons0;
12220 
12221  cons0 = conss[i];
12222  assert(cons0 != NULL);
12223 
12224  consdata0 = SCIPconsGetData(cons0);
12225  assert(consdata0 != NULL);
12226 
12227  consdataCalcSignature(consdata0);
12228  assert(consdata0->validsignature);
12229 
12230  for( j = i+1; j < nconss; ++j )
12231  {
12232  SCIP_CONSDATA* consdata1;
12233  SCIP_CONS* cons1;
12234 
12235  cons1 = conss[j];
12236  assert(cons1 != NULL);
12237 
12238  consdata1 = SCIPconsGetData(cons1);
12239  assert(consdata1 != NULL);
12240 
12241  if( consdata0->capacity != consdata1->capacity )
12242  continue;
12243 
12244  consdataCalcSignature(consdata1);
12245  assert(consdata1->validsignature);
12246 
12247  if( (consdata1->signature & (~consdata0->signature)) == 0 )
12248  {
12249  SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12250  SCIPswapPointers((void**)&cons0, (void**)&cons1);
12251  assert((consdata0->signature & (~consdata1->signature)) == 0);
12252  }
12253 
12254  if( (consdata0->signature & (~consdata1->signature)) == 0 )
12255  {
12256  int* perm0;
12257  int* perm1;
12258  int v0;
12259  int v1;
12260 
12261  if( consdata0->nvars > consdata1->nvars )
12262  continue;
12263 
12264  if( consdata0->hmin < consdata1->hmin )
12265  continue;
12266 
12267  if( consdata0->hmax > consdata1->hmax )
12268  continue;
12269 
12270  SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12271  SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12272 
12273  /* call sorting method */
12274  SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12275  SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12276 
12277  for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12278  {
12279  SCIP_VAR* var0;
12280  SCIP_VAR* var1;
12281  int idx0;
12282  int idx1;
12283  int comp;
12284 
12285  idx0 = perm0[v0];
12286  idx1 = perm1[v1];
12287 
12288  var0 = consdata0->vars[idx0];
12289 
12290  var1 = consdata1->vars[idx1];
12291 
12292  comp = SCIPvarCompare(var0, var1);
12293 
12294  if( comp == 0 )
12295  {
12296  int duration0;
12297  int duration1;
12298  int demand0;
12299  int demand1;
12300 
12301  demand0 = consdata0->demands[idx0];
12302  duration0 = consdata0->durations[idx0];
12303 
12304  demand1 = consdata1->demands[idx1];
12305  duration1 = consdata1->durations[idx1];
12306 
12307  if( demand0 != demand1 )
12308  break;
12309 
12310  if( duration0 != duration1 )
12311  break;
12312 
12313  v0++;
12314  v1++;
12315  }
12316  else if( comp > 0 )
12317  v1++;
12318  else
12319  break;
12320  }
12321 
12322  if( v0 == consdata0->nvars )
12323  {
12324  if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12325  {
12326  initializeLocks(consdata1, TRUE);
12327  }
12328 
12329  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12330 
12331  SCIP_CALL( SCIPdelCons(scip, cons0) );
12332  (*ndelconss)++;
12333  }
12334 
12335  SCIPfreeBufferArray(scip, &perm1);
12336  SCIPfreeBufferArray(scip, &perm0);
12337  }
12338  }
12339  }
12340 
12341  return SCIP_OKAY;
12342 }
12343 
12344 /** strengthen the variable bounds using the cumulative condition */
12345 static
12347  SCIP* scip, /**< SCIP data structure */
12348  SCIP_CONS* cons, /**< constraint to propagate */
12349  int* nchgbds, /**< pointer to store the number of changed bounds */
12350  int* naddconss /**< pointer to store the number of added constraints */
12351  )
12352 {
12353  SCIP_CONSDATA* consdata;
12354  SCIP_VAR** vars;
12355  int* durations;
12356  int* demands;
12357  int capacity;
12358  int nvars;
12359  int nconss;
12360  int i;
12361 
12362  consdata = SCIPconsGetData(cons);
12363  assert(consdata != NULL);
12364 
12365  /* check if the variable bounds got already strengthen by the cumulative constraint */
12366  if( consdata->varbounds )
12367  return SCIP_OKAY;
12368 
12369  vars = consdata->vars;
12370  durations = consdata->durations;
12371  demands = consdata->demands;
12372  capacity = consdata->capacity;
12373  nvars = consdata->nvars;
12374 
12375  nconss = 0;
12376 
12377  for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12378  {
12379  SCIP_VAR** vbdvars;
12380  SCIP_VAR* var;
12381  SCIP_Real* vbdcoefs;
12382  SCIP_Real* vbdconsts;
12383  int nvbdvars;
12384  int b;
12385  int j;
12386 
12387  var = consdata->vars[i];
12388  assert(var != NULL);
12389 
12390  vbdvars = SCIPvarGetVlbVars(var);
12391  vbdcoefs = SCIPvarGetVlbCoefs(var);
12392  vbdconsts = SCIPvarGetVlbConstants(var);
12393  nvbdvars = SCIPvarGetNVlbs(var);
12394 
12395  for( b = 0; b < nvbdvars; ++b )
12396  {
12397  if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12398  {
12399  if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12400  {
12401  for( j = 0; j < nvars; ++j )
12402  {
12403  if( vars[j] == vbdvars[b] )
12404  break;
12405  }
12406  if( j == nvars )
12407  continue;
12408 
12409  if( demands[i] + demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12410  {
12411  SCIP_Bool infeasible;
12412  char name[SCIP_MAXSTRLEN];
12413  int nlocalbdchgs;
12414 
12415  SCIPdebugMessage("<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12416 
12417  /* construct constraint name */
12418  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12419 
12420  SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12421  nconss++;
12422 
12423  SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12424  assert(!infeasible);
12425 
12426  (*nchgbds) += nlocalbdchgs;
12427  }
12428  }
12429  }
12430  }
12431  }
12432 
12433  (*naddconss) += nconss;
12434 
12435  consdata->varbounds = TRUE;
12436 
12437  return SCIP_OKAY;
12438 }
12439 
12440 /**@} */
12441 
12442 
12443 /**@name Callback methods of constraint handler
12444  *
12445  * @{
12446  */
12447 
12448 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12449 static
12450 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12451 { /*lint --e{715}*/
12452  assert(scip != NULL);
12453  assert(conshdlr != NULL);
12454  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12455 
12456  /* call inclusion method of constraint handler */
12458 
12460 
12461  *valid = TRUE;
12462 
12463  return SCIP_OKAY;
12464 }
12465 
12466 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12467 static
12468 SCIP_DECL_CONSFREE(consFreeCumulative)
12469 { /*lint --e{715}*/
12470  SCIP_CONSHDLRDATA* conshdlrdata;
12471 
12472  assert(conshdlr != NULL);
12473  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12474 
12475  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12476  assert(conshdlrdata != NULL);
12477 
12478 #ifdef SCIP_STATISTIC
12479  if( !conshdlrdata->iscopy )
12480  {
12481  /* statisitc output if SCIP_STATISTIC is defined */
12482  SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12483  conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12484  SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12485  conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12486  SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12487  conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12488  }
12489 #endif
12490 
12491  conshdlrdataFree(scip, &conshdlrdata);
12492 
12493  SCIPconshdlrSetData(conshdlr, NULL);
12494 
12495  return SCIP_OKAY;
12496 }
12497 
12498 
12499 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12500 static
12501 SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12502 { /*lint --e{715}*/
12503  SCIP_CONSHDLRDATA* conshdlrdata;
12504  int c;
12505 
12506  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12507  assert(conshdlrdata != NULL);
12508 
12509  conshdlrdata->detectedredundant = FALSE;
12510 
12511  for( c = 0; c < nconss; ++c )
12512  {
12513  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12514  * hmax)
12515  */
12516  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12517  }
12518 
12519  return SCIP_OKAY;
12520 }
12521 
12522 
12523 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12524 #ifdef SCIP_STATISTIC
12525 static
12526 SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12527 { /*lint --e{715}*/
12528  SCIP_CONSHDLRDATA* conshdlrdata;
12529  int c;
12530 
12531  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12532  assert(conshdlrdata != NULL);
12533 
12534  for( c = 0; c < nconss; ++c )
12535  {
12536  SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12537 
12538 #if 0
12539  SCIP_CALL( SCIPvisualizeConsCumulative(scip, conss[c]) );
12540 #endif
12541  }
12542 
12543  if( !conshdlrdata->iscopy )
12544  {
12545  SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12546  SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12547  SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12548  SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12549  SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12550  SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12551  SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12552  SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12553  SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12554  }
12555 
12556  return SCIP_OKAY;
12557 }
12558 #endif
12559 
12560 
12561 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12562 static
12563 SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12564 { /*lint --e{715}*/
12565  SCIP_CONSDATA* consdata;
12566  int c;
12567 
12568  assert(conshdlr != NULL);
12569  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12570 
12571  /* release the rows of all constraints */
12572  for( c = 0; c < nconss; ++c )
12573  {
12574  consdata = SCIPconsGetData(conss[c]);
12575  assert(consdata != NULL);
12576 
12577  /* free rows */
12578  SCIP_CALL( consdataFreeRows(scip, &consdata) );
12579  }
12580 
12581  return SCIP_OKAY;
12582 }
12583 
12584 /** frees specific constraint data */
12585 static
12586 SCIP_DECL_CONSDELETE(consDeleteCumulative)
12587 { /*lint --e{715}*/
12588  assert(conshdlr != NULL);
12589  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12590  assert(consdata != NULL );
12591  assert(*consdata != NULL );
12592 
12593  /* if constraint belongs to transformed problem space, drop bound change events on variables */
12594  if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12595  {
12596  SCIP_CONSHDLRDATA* conshdlrdata;
12597 
12598  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12599  assert(conshdlrdata != NULL);
12600 
12601  SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12602  }
12603 
12604  /* free cumulative constraint data */
12605  SCIP_CALL( consdataFree(scip, consdata) );
12606 
12607  return SCIP_OKAY;
12608 }
12609 
12610 /** transforms constraint data into data belonging to the transformed problem */
12611 static
12612 SCIP_DECL_CONSTRANS(consTransCumulative)
12613 { /*lint --e{715}*/
12614  SCIP_CONSHDLRDATA* conshdlrdata;
12615  SCIP_CONSDATA* sourcedata;
12616  SCIP_CONSDATA* targetdata;
12617 
12618  assert(conshdlr != NULL);
12619  assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
12620  assert(sourcecons != NULL);
12621  assert(targetcons != NULL);
12622 
12623  sourcedata = SCIPconsGetData(sourcecons);
12624  assert(sourcedata != NULL);
12625  assert(sourcedata->demandrows == NULL);
12626 
12627  SCIPdebugMessage("transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12628 
12629  /* get event handler */
12630  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12631  assert(conshdlrdata != NULL);
12632  assert(conshdlrdata->eventhdlr != NULL);
12633 
12634  /* create constraint data for target constraint */
12635  SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12636  sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12637  sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12638 
12639  /* create target constraint */
12640  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12641  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12642  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12643  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12644  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12645 
12646  /* catch bound change events of variables */
12647  SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12648 
12649  return SCIP_OKAY;
12650 }
12651 
12652 /** LP initialization method of constraint handler */
12653 static
12654 SCIP_DECL_CONSINITLP(consInitlpCumulative)
12656  SCIP_CONSHDLRDATA* conshdlrdata;
12657  int c;
12658 
12659  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12660  assert(conshdlr != NULL);
12661  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12662  assert(conshdlrdata != NULL);
12663 
12664  SCIPdebugMessage("initialize LP relaxation for %d cumulative constraints\n", nconss);
12665 
12666  if( conshdlrdata->usebinvars )
12667  {
12668  /* add rows to LP */
12669  for( c = 0; c < nconss; ++c )
12670  {
12671  assert(SCIPconsIsInitial(conss[c]));
12672  SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss) );
12673 
12674  if( conshdlrdata->cutsasconss )
12675  {
12676  SCIP_CALL( SCIPrestartSolve(scip) );
12677  }
12678  }
12679  }
12680 
12681  /**@todo if we want to use only the integer variables; only these will be in cuts
12682  * create some initial cuts, currently these are only separated */
12683 
12684  return SCIP_OKAY;
12685 }
12686 
12687 /** separation method of constraint handler for LP solutions */
12688 static
12689 SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12691  SCIP_CONSHDLRDATA* conshdlrdata;
12692  SCIP_Bool cutoff;
12693  SCIP_Bool reducedom;
12694  SCIP_Bool separated;
12695  int c;
12696 
12697  SCIPdebugMessage("consSepalpCumulative\n");
12698 
12699  assert(conshdlr != NULL);
12700  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12701  assert(nconss == 0 || conss != NULL);
12702  assert(result != NULL);
12703  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12704  assert(conshdlrdata != NULL);
12705 
12706  SCIPdebugMessage("separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12707 
12708  cutoff = FALSE;
12709  reducedom = FALSE;
12710  separated = FALSE;
12711  (*result) = SCIP_DIDNOTRUN;
12712 
12713  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12714  return SCIP_OKAY;
12715 
12716  (*result) = SCIP_DIDNOTFIND;
12717 
12718  if( conshdlrdata->usebinvars )
12719  {
12720  /* check all useful cumulative constraints for feasibility */
12721  for( c = 0; c < nusefulconss && !reducedom && !cutoff; ++c )
12722  {
12723  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12724  }
12725 
12726  if( !cutoff && !reducedom && conshdlrdata->usecovercuts )
12727  {
12728  for( c = 0; c < nusefulconss; ++c )
12729  {
12730  SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12731  }
12732  }
12733  }
12734 
12735  if( conshdlrdata->sepaold )
12736  {
12737  /* separate cuts containing only integer variables */
12738  for( c = 0; c < nusefulconss; ++c )
12739  {
12740  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated) );
12741  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated) );
12742  }
12743  }
12744 
12745  if( cutoff )
12746  *result = SCIP_CUTOFF;
12747  else if( reducedom )
12748  *result = SCIP_REDUCEDDOM;
12749  else if( separated )
12750  *result = SCIP_SEPARATED;
12751 
12752  return SCIP_OKAY;
12753 }
12754 
12755 /** separation method of constraint handler for arbitrary primal solutions */
12756 static
12757 SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12758 { /*lint --e{715}*/
12759  SCIP_CONSHDLRDATA* conshdlrdata;
12760  SCIP_Bool cutoff;
12761  SCIP_Bool reducedom;
12762  SCIP_Bool separated;
12763  int c;
12764 
12765  assert(conshdlr != NULL);
12766  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12767  assert(nconss == 0 || conss != NULL);
12768  assert(result != NULL);
12769 
12770  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12771  assert(conshdlrdata != NULL);
12772 
12773  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12774  return SCIP_OKAY;
12775 
12776  SCIPdebugMessage("separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12777 
12778  cutoff = FALSE;
12779  reducedom = FALSE;
12780  separated = FALSE;
12781  (*result) = SCIP_DIDNOTFIND;
12782 
12783  if( conshdlrdata->usebinvars )
12784  {
12785  /* check all useful cumulative constraints for feasibility */
12786  for( c = 0; c < nusefulconss && !cutoff && !reducedom; ++c )
12787  {
12788  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12789  }
12790 
12791  if( !cutoff && !reducedom && conshdlrdata->usecovercuts )
12792  {
12793  for( c = 0; c < nusefulconss; ++c )
12794  {
12795  SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12796  }
12797  }
12798  }
12799  if( conshdlrdata->sepaold )
12800  {
12801  /* separate cuts containing only integer variables */
12802  for( c = 0; c < nusefulconss; ++c )
12803  {
12804  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated) );
12805  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated) );
12806  }
12807  }
12808 
12809  if( cutoff )
12810  *result = SCIP_CUTOFF;
12811  else if( reducedom )
12812  *result = SCIP_REDUCEDDOM;
12813  else if( separated )
12814  *result = SCIP_SEPARATED;
12815 
12816  return SCIP_OKAY;
12817 }
12818 
12819 /** constraint enforcing method of constraint handler for LP solutions */
12820 static
12821 SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
12822 { /*lint --e{715}*/
12823  SCIP_CONSHDLRDATA* conshdlrdata;
12824 
12825  assert(conshdlr != NULL);
12826  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12827  assert(nconss == 0 || conss != NULL);
12828  assert(result != NULL);
12829 
12830  if( solinfeasible )
12831  {
12832  *result = SCIP_INFEASIBLE;
12833  return SCIP_OKAY;
12834  }
12835 
12836  SCIPdebugMessage("LP enforcing %d useful cumulative constraints of %d constraints\n", nusefulconss, nconss);
12837 
12838  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12839  assert(conshdlrdata != NULL);
12840 
12841  (*result) = SCIP_FEASIBLE;
12842 
12843  if( conshdlrdata->usebinvars )
12844  {
12845  SCIP_Bool separated;
12846  SCIP_Bool cutoff;
12847  int c;
12848 
12849  separated = FALSE;
12850 
12851  /* first check if a constraints is violated */
12852  for( c = 0; c < nusefulconss; ++c )
12853  {
12854  SCIP_CONS* cons;
12855  SCIP_Bool violated;
12856 
12857  cons = conss[c];
12858  assert(cons != NULL);
12859 
12860  SCIP_CALL( checkCons(scip, cons, NULL, &violated, FALSE) );
12861 
12862  if( !violated )
12863  continue;
12864 
12865  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, NULL, &separated, &cutoff) );
12866  if ( cutoff )
12867  {
12868  *result = SCIP_CUTOFF;
12869  return SCIP_OKAY;
12870  }
12871  }
12872 
12873  for( ; c < nconss && !separated; ++c )
12874  {
12875  SCIP_CONS* cons;
12876  SCIP_Bool violated;
12877 
12878  cons = conss[c];
12879  assert(cons != NULL);
12880 
12881  SCIP_CALL( checkCons(scip, cons, NULL, &violated, FALSE) );
12882 
12883  if( !violated )
12884  continue;
12885 
12886  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, NULL, &separated, &cutoff) );
12887  if ( cutoff )
12888  {
12889  *result = SCIP_CUTOFF;
12890  return SCIP_OKAY;
12891  }
12892  }
12893 
12894  if( separated )
12895  (*result) = SCIP_SEPARATED;
12896  }
12897  else
12898  {
12899  SCIP_CALL( enforceSolution(scip, conss, nconss, conshdlrdata->fillbranchcands, result) );
12900  }
12901 
12902  return SCIP_OKAY;
12903 }
12904 
12905 /** constraint enforcing method of constraint handler for pseudo solutions */
12906 static
12907 SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
12908 { /*lint --e{715}*/
12909  SCIP_CONSHDLRDATA* conshdlrdata;
12910 
12911  SCIPdebugMessage("method: enforce pseudo solution\n");
12912 
12913  assert(conshdlr != NULL);
12914  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12915  assert(nconss == 0 || conss != NULL);
12916  assert(result != NULL);
12917 
12918  if( objinfeasible )
12919  {
12920  *result = SCIP_DIDNOTRUN;
12921  return SCIP_OKAY;
12922  }
12923 
12924  (*result) = SCIP_FEASIBLE;
12925 
12926  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12927  assert(conshdlrdata != NULL);
12928 
12929  SCIP_CALL( enforceSolution(scip, conss, nconss, conshdlrdata->fillbranchcands, result) );
12930 
12931  return SCIP_OKAY;
12932 }
12933 
12934 /** feasibility check method of constraint handler for integral solutions */
12935 static
12936 SCIP_DECL_CONSCHECK(consCheckCumulative)
12937 { /*lint --e{715}*/
12938  SCIP_Bool violated;
12939  int c;
12940 
12941  assert(conshdlr != NULL);
12942  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12943  assert(nconss == 0 || conss != NULL);
12944  assert(result != NULL);
12945 
12946  violated = FALSE;
12947 
12948  SCIPdebugMessage("check %d cumulative constraints\n", nconss);
12949 
12950  for( c = 0; c < nconss && !violated; ++c )
12951  {
12952  SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
12953  }
12954 
12955  if( violated )
12956  *result = SCIP_INFEASIBLE;
12957  else
12958  *result = SCIP_FEASIBLE;
12959 
12960  return SCIP_OKAY;
12961 }
12962 
12963 /** domain propagation method of constraint handler */
12964 static
12965 SCIP_DECL_CONSPROP(consPropCumulative)
12966 { /*lint --e{715}*/
12967  SCIP_CONSHDLRDATA* conshdlrdata;
12968  SCIP_Bool cutoff;
12969  int nchgbds;
12970  int ndelconss;
12971  int c;
12972 #if 0
12973  int naggrvars = 0;
12974 #endif
12975 
12976  SCIPdebugMessage("propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
12977 
12978  assert(conshdlr != NULL);
12979  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12980  assert(nconss == 0 || conss != NULL);
12981  assert(result != NULL);
12982 
12983  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12984  assert(conshdlrdata != NULL);
12985 
12986  nchgbds = 0;
12987  ndelconss = 0;
12988  cutoff = FALSE;
12989  (*result) = SCIP_DIDNOTRUN;
12990 
12991  /* propgate all useful constraints */
12992  for( c = 0; c < nusefulconss && !cutoff; ++c )
12993  {
12994  SCIP_CONS* cons;
12995 
12996  cons = conss[c];
12997  assert(cons != NULL);
12998 
12999  if( SCIPgetDepth(scip) == 0 )
13000  {
13001 #if 0
13002  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13003  &nchgbds, &naggrvars, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13004 #else
13005  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13006  &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13007 #endif
13008  if( cutoff )
13009  break;
13010 
13011  if( SCIPconsIsDeleted(cons) )
13012  continue;
13013  }
13014 
13015  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13016  }
13017 
13018  if( !cutoff && nchgbds == 0 )
13019  {
13020  /* propgate all other constraints */
13021  for( c = nusefulconss; c < nconss && !cutoff; ++c )
13022  {
13023  SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13024  }
13025  }
13026 
13027 #if 0
13028  if( !cutoff && conshdlrdata->dualpresolve && SCIPallowDualReds(scip) && nconss > 1 )
13029  {
13030  SCIP_CALL( propagateAllConss(scip, conshdlrdata, conss, nconss, TRUE, &nchgbds, &cutoff, NULL) );
13031  }
13032 #endif
13033 
13034  if( cutoff )
13035  {
13036  SCIPdebugMessage("detected infeasible\n");
13037  *result = SCIP_CUTOFF;
13038  }
13039  else if( nchgbds > 0 )
13040  {
13041  SCIPdebugMessage("delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13042  *result = SCIP_REDUCEDDOM;
13043  }
13044  else
13045  *result = SCIP_DIDNOTFIND;
13046 
13047  return SCIP_OKAY;
13048 }
13049 
13050 /** presolving method of constraint handler */
13051 static
13052 SCIP_DECL_CONSPRESOL(consPresolCumulative)
13053 { /*lint --e{715}*/
13054  SCIP_CONSHDLRDATA* conshdlrdata;
13055  SCIP_CONS* cons;
13056  SCIP_Bool cutoff;
13057  SCIP_Bool unbounded;
13058  int oldnfixedvars;
13059  int oldnchgbds;
13060  int oldndelconss;
13061  int oldnaddconss;
13062  int oldnupgdconss;
13063  int oldnchgsides;
13064  int oldnchgcoefs;
13065  int c;
13066 
13067  assert(conshdlr != NULL);
13068  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13069  assert(scip != NULL);
13070  assert(result != NULL);
13071 
13072  SCIPdebugMessage("presolve %d cumulative constraints\n", nconss);
13073 
13074  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13075  assert(conshdlrdata != NULL);
13076 
13077  *result = SCIP_DIDNOTRUN;
13078 
13079  oldnfixedvars = *nfixedvars;
13080  oldnchgbds = *nchgbds;
13081  oldnchgsides = *nchgsides;
13082  oldnchgcoefs = *nchgcoefs;
13083  oldnupgdconss = *nupgdconss;
13084  oldndelconss = *ndelconss;
13085  oldnaddconss = *naddconss;
13086  cutoff = FALSE;
13087  unbounded = FALSE;
13088 
13089  /* process constraints */
13090  for( c = 0; c < nconss && !cutoff; ++c )
13091  {
13092  cons = conss[c];
13093 
13094  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13095  * hmax)
13096  */
13097  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13098 
13099  if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13100  {
13101 #if 0
13102  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13103  nfixedvars, naggrvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13104 #else
13105  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13106  nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13107 #endif
13108 
13109  if( cutoff || unbounded )
13110  break;
13111 
13112  if( SCIPconsIsDeleted(cons) )
13113  continue;
13114  }
13115 
13116  /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13117  if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13118  {
13119  SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13120  }
13121 
13122  /* strengthen existing variable bounds using the cumulative condition */
13123  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13124  {
13125  SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13126  }
13127 
13128  /* propagate cumulative constraint */
13129  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13130  assert(checkDemands(scip, cons) || cutoff);
13131  }
13132 
13133  if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13134  {
13135  SCIP_CALL( propagateAllConss(scip, conshdlrdata, conss, nconss, FALSE,
13136  nfixedvars, &cutoff, NULL) );
13137  }
13138 
13139  /* only perform the detection of variable bounds and disjunctive constraint once */
13140  if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13141  && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13142  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13143  {
13144  /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13145  * propagation
13146  */
13147  SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13148  conshdlrdata->detectedredundant = TRUE;
13149  }
13150 
13151  if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13152  {
13153  SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13154  }
13155 
13156  SCIPdebugMessage("delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13157  *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13158 
13159  if( cutoff )
13160  *result = SCIP_CUTOFF;
13161  else if( unbounded )
13162  *result = SCIP_UNBOUNDED;
13163  else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13164  || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13165  *result = SCIP_SUCCESS;
13166  else
13167  *result = SCIP_DIDNOTFIND;
13168 
13169  return SCIP_OKAY;
13170 }
13171 
13172 /** propagation conflict resolving method of constraint handler */
13173 static
13174 SCIP_DECL_CONSRESPROP(consRespropCumulative)
13175 { /*lint --e{715}*/
13176  SCIP_CONSHDLRDATA* conshdlrdata;
13177  SCIP_CONSDATA* consdata;
13178 
13179  assert(conshdlr != NULL);
13180  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13181  assert(scip != NULL);
13182  assert(result != NULL);
13183  assert(infervar != NULL);
13184  assert(bdchgidx != NULL);
13185 
13186  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13187  assert(conshdlrdata != NULL);
13188 
13189  /* process constraint */
13190  assert(cons != NULL);
13191 
13192  consdata = SCIPconsGetData(cons);
13193  assert(consdata != NULL);
13194 
13195  SCIPdebugMessage("resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13196  SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13197  SCIPgetHminCumulative(scip, cons), SCIPgetHmaxCumulative(scip, cons));
13198 
13199  SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13200  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13201  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13202 
13203  return SCIP_OKAY;
13204 }
13205 
13206 /** variable rounding lock method of constraint handler */
13207 static
13208 SCIP_DECL_CONSLOCK(consLockCumulative)
13209 { /*lint --e{715}*/
13210  SCIP_CONSDATA* consdata;
13211  SCIP_VAR** vars;
13212  int v;
13213 
13214  SCIPdebugMessage("lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13215 
13216  assert(scip != NULL);
13217  assert(cons != NULL);
13218 
13219  consdata = SCIPconsGetData(cons);
13220  assert(consdata != NULL);
13221 
13222  vars = consdata->vars;
13223  assert(vars != NULL);
13224 
13225  for( v = 0; v < consdata->nvars; ++v )
13226  {
13227  if( consdata->downlocks[v] && consdata->uplocks[v] )
13228  {
13229  /* the integer start variable should not get rounded in both direction */
13230  SCIP_CALL( SCIPaddVarLocks(scip, vars[v], nlockspos + nlocksneg, nlockspos + nlocksneg) );
13231  }
13232  else if( consdata->downlocks[v] )
13233  {
13234  SCIP_CALL( SCIPaddVarLocks(scip, vars[v], nlockspos, nlocksneg) );
13235  }
13236  else if( consdata->uplocks[v] )
13237  {
13238  SCIP_CALL( SCIPaddVarLocks(scip, vars[v], nlocksneg, nlockspos) );
13239  }
13240  }
13241 
13242  return SCIP_OKAY;
13243 }
13244 
13245 
13246 /** constraint display method of constraint handler */
13247 static
13248 SCIP_DECL_CONSPRINT(consPrintCumulative)
13249 { /*lint --e{715}*/
13250  assert(scip != NULL);
13251  assert(conshdlr != NULL);
13252  assert(cons != NULL);
13253 
13254  consdataPrint(scip, SCIPconsGetData(cons), file);
13255 
13256  return SCIP_OKAY;
13257 }
13258 
13259 /** constraint copying method of constraint handler */
13260 static
13261 SCIP_DECL_CONSCOPY(consCopyCumulative)
13262 { /*lint --e{715}*/
13263  SCIP_CONSDATA* sourceconsdata;
13264  SCIP_VAR** sourcevars;
13265  SCIP_VAR** vars;
13266  const char* consname;
13267 
13268  int nvars;
13269  int v;
13270 
13271  sourceconsdata = SCIPconsGetData(sourcecons);
13272  assert(sourceconsdata != NULL);
13273 
13274  /* get variables of the source constraint */
13275  nvars = sourceconsdata->nvars;
13276  sourcevars = sourceconsdata->vars;
13277 
13278  (*valid) = TRUE;
13279 
13280  if( nvars == 0 )
13281  return SCIP_OKAY;
13282 
13283  /* allocate buffer array */
13284  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13285 
13286  for( v = 0; v < nvars && *valid; ++v )
13287  {
13288  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13289  assert(!(*valid) || vars[v] != NULL);
13290  }
13291 
13292  /* only create the target constraint, if all variables could be copied */
13293  if( *valid )
13294  {
13295  if( name != NULL )
13296  consname = name;
13297  else
13298  consname = SCIPconsGetName(sourcecons);
13299 
13300  /* create a copy of the cumulative constraint */
13301  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13302  sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13303  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13304 
13305  /* adjust left side if the time axis if needed */
13306  if( sourceconsdata->hmin > 0 )
13307  {
13308  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13309  }
13310 
13311  /* adjust right side if the time axis if needed */
13312  if( sourceconsdata->hmax < INT_MAX )
13313  {
13314  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13315  }
13316  }
13317 
13318  /* free buffer array */
13319  SCIPfreeBufferArray(scip, &vars);
13320 
13321  return SCIP_OKAY;
13322 }
13323 
13324 
13325 /** constraint parsing method of constraint handler */
13326 static
13327 SCIP_DECL_CONSPARSE(consParseCumulative)
13328 { /*lint --e{715}*/
13329  SCIP_VAR** vars;
13330  SCIP_VAR* var;
13331  SCIP_Real value;
13332  char strvalue[SCIP_MAXSTRLEN];
13333  char* endptr;
13334  int* demands;
13335  int* durations;
13336  int capacity;
13337  int duration;
13338  int demand;
13339  int hmin;
13340  int hmax;
13341  int varssize;
13342  int nvars;
13343 
13344  SCIPdebugMessage("parse <%s> as cumulative constraint\n", str);
13345 
13346  /* cutoff "cumulative" form the constraint string */
13347  SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13348  str = endptr;
13349 
13350  varssize = 100;
13351  nvars = 0;
13352 
13353  /* allocate buffer array for variables */
13354  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13355  SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13356  SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13357 
13358  do
13359  {
13360  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13361 
13362  if( var != NULL )
13363  {
13364  str = endptr;
13365 
13366  SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13367  duration = atoi(strvalue);
13368  str = endptr;
13369 
13370  SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13371  demand = atoi(strvalue);
13372  str = endptr;
13373 
13374  SCIPdebugMessage("parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13375 
13376  vars[nvars] = var;
13377  demands[nvars] = demand;
13378  durations[nvars] = duration;
13379  nvars++;
13380  }
13381  }
13382  while( var != NULL );
13383 
13384  /* parse effective time window */
13385  SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13386  hmin = atoi(strvalue);
13387  str = endptr;
13388 
13389  if( SCIPstrToRealValue(str, &value, &endptr) )
13390  {
13391  hmax = (int)(value);
13392  str = endptr;
13393 
13394  /* parse capacity */
13395  SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13396  str = endptr;
13397  if( SCIPstrToRealValue(str, &value, &endptr) )
13398  {
13399  capacity = (int)value;
13400 
13401  /* create cumulative constraint */
13402  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13403  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13404 
13405  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13406  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13407 
13408  (*success) = TRUE;
13409  }
13410  }
13411 
13412  /* free buffer arrays */
13413  SCIPfreeBufferArray(scip, &durations);
13414  SCIPfreeBufferArray(scip, &demands);
13415  SCIPfreeBufferArray(scip, &vars);
13416 
13417  return SCIP_OKAY;
13418 }
13419 
13420 /** constraint method of constraint handler which returns the variables (if possible) */
13421 static
13422 SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13423 { /*lint --e{715}*/
13424  SCIP_CONSDATA* consdata;
13425 
13426  consdata = SCIPconsGetData(cons);
13427  assert(consdata != NULL);
13428 
13429  if( varssize < consdata->nvars )
13430  (*success) = FALSE;
13431  else
13432  {
13433  assert(vars != NULL);
13434 
13435  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13436  (*success) = TRUE;
13437  }
13438 
13439  return SCIP_OKAY;
13440 }
13441 
13442 /** constraint method of constraint handler which returns the number of variables (if possible) */
13443 static
13444 SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13445 { /*lint --e{715}*/
13446  SCIP_CONSDATA* consdata;
13447 
13448  consdata = SCIPconsGetData(cons);
13449  assert(consdata != NULL);
13450 
13451  (*nvars) = consdata->nvars;
13452  (*success) = TRUE;
13453 
13454  return SCIP_OKAY;
13455 }
13456 
13457 /**@} */
13458 
13459 /**@name Callback methods of event handler
13460  *
13461  * @{
13462  */
13463 
13464 
13465 /** execution method of event handler */
13466 static
13467 SCIP_DECL_EVENTEXEC(eventExecCumulative)
13468 { /*lint --e{715}*/
13469  SCIP_CONSDATA* consdata;
13470 
13471  assert(scip != NULL);
13472  assert(eventhdlr != NULL);
13473  assert(eventdata != NULL);
13474  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13475  assert(event != NULL);
13476 
13477  consdata = (SCIP_CONSDATA*)eventdata;
13478  assert(consdata != NULL);
13479 
13480  /* mark the constraint to be not propagated */
13481  consdata->propagated = FALSE;
13482 
13483  return SCIP_OKAY;
13484 }
13485 
13486 /**@} */
13487 
13488 /**@name Interface methods
13489  *
13490  * @{
13491  */
13492 
13493 /*
13494  * constraint specific interface methods
13495  */
13496 
13497 /** creates the handler for cumulative constraints and includes it in SCIP */
13499  SCIP* scip /**< SCIP data structure */
13500  )
13501 {
13502  SCIP_CONSHDLRDATA* conshdlrdata;
13503  SCIP_CONSHDLR* conshdlr;
13504  SCIP_EVENTHDLR* eventhdlr;
13505 
13506  /* create event handler for bound change events */
13507  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13508 
13509  /* create cumulative constraint handler data */
13510  SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13511 
13512  /* include constraint handler */
13515  consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13516  conshdlrdata) );
13517 
13518  assert(conshdlr != NULL);
13519 
13520  /* set non-fundamental callbacks via specific setter functions */
13521  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13522  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13523 #ifdef SCIP_STATISTIC
13524  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13525 #endif
13526  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13527  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13528  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13529  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13530  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13531  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13532  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13533  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13535  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13536  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropCumulative, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13538  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13539  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13541  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13542 
13543  /* add cumulative constraint handler parameters */
13545  "constraints/" CONSHDLR_NAME "/ttinfer",
13546  "should time-table (core-times) propagator be used to infer bounds?",
13547  &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13549  "constraints/" CONSHDLR_NAME "/efcheck",
13550  "should edge-finding be used to detect an overload?",
13551  &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13553  "constraints/" CONSHDLR_NAME "/efinfer",
13554  "should edge-finding be used to infer bounds?",
13555  &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13557  "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13558  &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13560  "constraints/" CONSHDLR_NAME "/ttefcheck",
13561  "should time-table edge-finding be used to detect an overload?",
13562  &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13564  "constraints/" CONSHDLR_NAME "/ttefinfer",
13565  "should time-table edge-finding be used to infer bounds?",
13566  &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13567 
13569  "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13570  &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13572  "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13573  &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13575  "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13576  &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13578  "constraints/" CONSHDLR_NAME "/cutsasconss",
13579  "should the cumulative constraint create cuts as knapsack constraints?",
13580  &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13582  "constraints/" CONSHDLR_NAME "/sepaold",
13583  "shall old sepa algo be applied?",
13584  &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13585 
13587  "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13588  &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13589 
13590  /* presolving parameters */
13592  "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13593  &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13595  "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13596  &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13598  "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13599  &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13601  "constraints/" CONSHDLR_NAME "/presolpairwise",
13602  "should pairwise constraint comparison be performed in presolving?",
13603  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13605  "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13606  &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13607 
13609  "constraints/" CONSHDLR_NAME "/maxnodes",
13610  "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13611  &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13613  "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13614  &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13616  "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13617  &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13618 
13619  /* conflict analysis parameters */
13621  "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13622  &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13623 
13624  return SCIP_OKAY;
13625 }
13626 
13627 /** creates and captures a cumulative constraint */
13629  SCIP* scip, /**< SCIP data structure */
13630  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13631  const char* name, /**< name of constraint */
13632  int nvars, /**< number of variables (jobs) */
13633  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13634  int* durations, /**< array containing corresponding durations */
13635  int* demands, /**< array containing corresponding demands */
13636  int capacity, /**< available cumulative capacity */
13637  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13638  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13639  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13640  * Usually set to TRUE. */
13641  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13642  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13643  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13644  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13645  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13646  * Usually set to TRUE. */
13647  SCIP_Bool local, /**< is constraint only valid locally?
13648  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13649  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13650  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13651  * adds coefficients to this constraint. */
13652  SCIP_Bool dynamic, /**< is constraint subject to aging?
13653  * Usually set to FALSE. Set to TRUE for own cuts which
13654  * are seperated as constraints. */
13655  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13656  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13657  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13658  * if it may be moved to a more global node?
13659  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13660  )
13661 {
13662  SCIP_CONSHDLR* conshdlr;
13663  SCIP_CONSDATA* consdata;
13664 
13665  assert(scip != NULL);
13666 
13667  /* find the cumulative constraint handler */
13668  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13669  if( conshdlr == NULL )
13670  {
13671  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13672  return SCIP_PLUGINNOTFOUND;
13673  }
13674 
13675  SCIPdebugMessage("create cumulative constraint <%s> with %d jobs\n", name, nvars);
13676 
13677  /* create constraint data */
13678  SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13679 
13680  /* create constraint */
13681  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13682  initial, separate, enforce, check, propagate,
13683  local, modifiable, dynamic, removable, stickingatnode) );
13684 
13685 
13686  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13687  {
13688  SCIP_CONSHDLRDATA* conshdlrdata;
13689 
13690  /* get event handler */
13691  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13692  assert(conshdlrdata != NULL);
13693  assert(conshdlrdata->eventhdlr != NULL);
13694 
13695  /* catch bound change events of variables */
13696  SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13697  }
13698 
13699  return SCIP_OKAY;
13700 }
13701 
13702 /** creates and captures a cumulative constraint
13703  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13704  * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13705  *
13706  * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13707  *
13708  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13709  */
13711  SCIP* scip, /**< SCIP data structure */
13712  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13713  const char* name, /**< name of constraint */
13714  int nvars, /**< number of variables (jobs) */
13715  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13716  int* durations, /**< array containing corresponding durations */
13717  int* demands, /**< array containing corresponding demands */
13718  int capacity /**< available cumulative capacity */
13719  )
13720 {
13721  assert(scip != NULL);
13722 
13723  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13724  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13725 
13726  return SCIP_OKAY;
13727 }
13728 
13729 /** set the left bound of the time axis to be considered (including hmin) */
13731  SCIP* scip, /**< SCIP data structure */
13732  SCIP_CONS* cons, /**< constraint data */
13733  int hmin /**< left bound of time axis to be considered */
13734  )
13735 {
13736  SCIP_CONSDATA* consdata;
13737  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13738  {
13739  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13740  return SCIP_INVALIDCALL;
13741  }
13742 
13743  consdata = SCIPconsGetData(cons);
13744  assert(consdata != NULL);
13745  assert(hmin >= 0);
13746  assert(hmin <= consdata->hmax);
13747 
13748  consdata->hmin = hmin;
13749 
13750  return SCIP_OKAY;
13751 }
13752 
13753 /** returns the left bound of the time axis to be considered */
13755  SCIP* scip, /**< SCIP data structure */
13756  SCIP_CONS* cons /**< constraint */
13757  )
13758 {
13759  SCIP_CONSDATA* consdata;
13760  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13761  {
13762  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13763  SCIPABORT();
13764  return 0; /*lint !e527*/
13765  }
13766 
13767  consdata = SCIPconsGetData(cons);
13768  assert(consdata != NULL);
13769 
13770  return consdata->hmin;
13771 }
13772 
13773 /** set the right bound of the time axis to be considered (not including hmax) */
13775  SCIP* scip, /**< SCIP data structure */
13776  SCIP_CONS* cons, /**< constraint data */
13777  int hmax /**< right bound of time axis to be considered */
13778  )
13779 {
13780  SCIP_CONSDATA* consdata;
13781  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13782  {
13783  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13784  SCIPABORT();
13785  return SCIP_INVALIDCALL; /*lint !e527*/
13786  }
13787 
13788  consdata = SCIPconsGetData(cons);
13789  assert(consdata != NULL);
13790  assert(hmax >= consdata->hmin);
13791 
13792  consdata->hmax = hmax;
13793 
13794  return SCIP_OKAY;
13795 }
13796 
13797 /** returns the right bound of the time axis to be considered */
13799  SCIP* scip, /**< SCIP data structure */
13800  SCIP_CONS* cons /**< constraint */
13801  )
13802 {
13803  SCIP_CONSDATA* consdata;
13804  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13805  {
13806  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13807  SCIPABORT();
13808  return 0; /*lint !e527*/
13809  }
13810 
13811  consdata = SCIPconsGetData(cons);
13812  assert(consdata != NULL);
13813 
13814  return consdata->hmax;
13815 }
13816 
13817 /** returns the activities of the cumulative constraint */
13819  SCIP* scip, /**< SCIP data structure */
13820  SCIP_CONS* cons /**< constraint data */
13821  )
13822 {
13823  SCIP_CONSDATA* consdata;
13824 
13825  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13826  {
13827  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13828  SCIPABORT();
13829  return NULL; /*lint !e527*/
13830  }
13831 
13832  consdata = SCIPconsGetData(cons);
13833  assert(consdata != NULL);
13834 
13835  return consdata->vars;
13836 }
13837 
13838 /** returns the activities of the cumulative constraint */
13840  SCIP* scip, /**< SCIP data structure */
13841  SCIP_CONS* cons /**< constraint data */
13842  )
13843 {
13844  SCIP_CONSDATA* consdata;
13845 
13846  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13847  {
13848  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13849  SCIPABORT();
13850  return -1; /*lint !e527*/
13851  }
13852 
13853  consdata = SCIPconsGetData(cons);
13854  assert(consdata != NULL);
13855 
13856  return consdata->nvars;
13857 }
13858 
13859 /** returns the capacity of the cumulative constraint */
13861  SCIP* scip, /**< SCIP data structure */
13862  SCIP_CONS* cons /**< constraint data */
13863  )
13864 {
13865  SCIP_CONSDATA* consdata;
13866 
13867  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13868  {
13869  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13870  SCIPABORT();
13871  return -1; /*lint !e527*/
13872  }
13873 
13874  consdata = SCIPconsGetData(cons);
13875  assert(consdata != NULL);
13876 
13877  return consdata->capacity;
13878 }
13879 
13880 /** returns the durations of the cumulative constraint */
13882  SCIP* scip, /**< SCIP data structure */
13883  SCIP_CONS* cons /**< constraint data */
13884  )
13885 {
13886  SCIP_CONSDATA* consdata;
13887 
13888  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13889  {
13890  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13891  SCIPABORT();
13892  return NULL; /*lint !e527*/
13893  }
13894 
13895  consdata = SCIPconsGetData(cons);
13896  assert(consdata != NULL);
13897 
13898  return consdata->durations;
13899 }
13900 
13901 /** returns the demands of the cumulative constraint */
13903  SCIP* scip, /**< SCIP data structure */
13904  SCIP_CONS* cons /**< constraint data */
13905  )
13906 {
13907  SCIP_CONSDATA* consdata;
13908 
13909  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13910  {
13911  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13912  SCIPABORT();
13913  return NULL; /*lint !e527*/
13914  }
13915 
13916  consdata = SCIPconsGetData(cons);
13917  assert(consdata != NULL);
13918 
13919  return consdata->demands;
13920 }
13921 
13922 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
13923  * given solution is satisfied
13924  */
13926  SCIP* scip, /**< SCIP data structure */
13927  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
13928  int nvars, /**< number of variables (jobs) */
13929  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13930  int* durations, /**< array containing corresponding durations */
13931  int* demands, /**< array containing corresponding demands */
13932  int capacity, /**< available cumulative capacity */
13933  int hmin, /**< left bound of time axis to be considered (including hmin) */
13934  int hmax, /**< right bound of time axis to be considered (not including hmax) */
13935  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
13936  SCIP_CONS* cons, /**< constraint which is checked */
13937  SCIP_Bool printreason /**< should the reason for the violation be printed? */
13938  )
13939 {
13940  assert(scip != NULL);
13941  assert(violated != NULL);
13942 
13943  SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
13944  violated, cons, printreason) );
13945 
13946  return SCIP_OKAY;
13947 }
13948 
13949 /** normalize cumulative condition */
13951  SCIP* scip, /**< SCIP data structure */
13952  int nvars, /**< number of start time variables (activities) */
13953  SCIP_VAR** vars, /**< array of start time variables */
13954  int* durations, /**< array of durations */
13955  int* demands, /**< array of demands */
13956  int* capacity, /**< pointer to store the changed cumulative capacity */
13957  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
13958  int* nchgsides /**< pointer to count number of side changes */
13959  )
13960 {
13961  SCIP_CALL( normalizeCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
13962  nchgcoefs, nchgsides) );
13963 
13964  return SCIP_OKAY;
13965 }
13966 
13967 /** searches for a time point within the cumulative condition were the cumulative condition can be split */
13969  SCIP* scip, /**< SCIP data structure */
13970  int nvars, /**< number of variables (jobs) */
13971  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13972  int* durations, /**< array containing corresponding durations */
13973  int* demands, /**< array containing corresponding demands */
13974  int capacity, /**< available cumulative capacity */
13975  int* hmin, /**< pointer to store the left bound of the effective horizon */
13976  int* hmax, /**< pointer to store the right bound of the effective horizon */
13977  int* split /**< point were the cumulative condition can be split */
13978  )
13979 {
13980  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
13981  hmin, hmax, split) );
13982 
13983  return SCIP_OKAY;
13984 }
13985 
13986 /** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
13988  SCIP* scip, /**< SCIP data structure */
13989  int nvars, /**< number of start time variables (activities) */
13990  SCIP_VAR** vars, /**< array of start time variables */
13991  int* durations, /**< array of durations */
13992  int hmin, /**< left bound of time axis to be considered */
13993  int hmax, /**< right bound of time axis to be considered (not including hmax) */
13994  SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
13995  SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
13996  SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
13997  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
13998  int* nfixedvars, /**< pointer to store the number of fixed variables */
13999  int* nchgsides, /**< pointer to store the number of changed sides */
14000  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
14001  )
14002 {
14003  if( nvars <= 1 )
14004  return SCIP_OKAY;
14005 
14006  /* presolve constraint form the earlier start time point of view */
14007  SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14008  irrelevants, nfixedvars, nchgsides, cutoff) );
14009 
14010  /* presolve constraint form the latest completion time point of view */
14011  SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14012  irrelevants, nfixedvars, nchgsides, cutoff) );
14013 
14014  return SCIP_OKAY;
14015 }
14016 
14017 /** propagate the given cumulative condition */
14019  SCIP* scip, /**< SCIP data structure */
14020  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
14021  int nvars, /**< number of variables (jobs) */
14022  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14023  int* durations, /**< array containing corresponding durations */
14024  int* demands, /**< array containing corresponding demands */
14025  int capacity, /**< available cumulative capacity */
14026  int hmin, /**< left bound of time axis to be considered (including hmin) */
14027  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14028  SCIP_CONS* cons, /**< constraint which gets propagated */
14029  int* nchgbds, /**< pointer to store the number of variable bound changes */
14030  SCIP_Bool* initialized, /**< was conflict analysis initialized */
14031  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14032  SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14033  )
14034 {
14035  SCIP_CONSHDLR* conshdlr;
14036  SCIP_CONSHDLRDATA* conshdlrdata;
14037  SCIP_Bool redundant;
14038 
14039  assert(scip != NULL);
14040  assert(cons != NULL);
14041  assert(initialized != NULL);
14042  assert(*initialized == FALSE);
14043  assert(cutoff != NULL);
14044  assert(*cutoff == FALSE);
14045 
14046  /* find the cumulative constraint handler */
14047  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14048  if( conshdlr == NULL )
14049  {
14050  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14051  return SCIP_PLUGINNOTFOUND;
14052  }
14053 
14054  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14055  assert(conshdlrdata != NULL);
14056 
14057  redundant = FALSE;
14058 
14059  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14060  nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14061  nchgbds, &redundant, initialized, explanation, cutoff) );
14062 
14063  return SCIP_OKAY;
14064 }
14065 
14066 /** resolve propagation w.r.t. the cumulative condition */
14068  SCIP* scip, /**< SCIP data structure */
14069  int nvars, /**< number of start time variables (activities) */
14070  SCIP_VAR** vars, /**< array of start time variables */
14071  int* durations, /**< array of durations */
14072  int* demands, /**< array of demands */
14073  int capacity, /**< cumulative capacity */
14074  int hmin, /**< left bound of time axis to be considered (including hmin) */
14075  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14076  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14077  int inferinfo, /**< the user information */
14078  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14079  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14080  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14081  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14082  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14083  )
14084 {
14085  SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14086  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14087 
14088  return SCIP_OKAY;
14089 }
14090 
14091 /** this method visualizes the cumulative structure in GML format */
14093  SCIP* scip, /**< SCIP data structure */
14094  SCIP_CONS* cons /**< cumulative constraint */
14095  )
14096 {
14097  SCIP_CONSDATA* consdata;
14098  SCIP_HASHTABLE* vars;
14099  FILE* file;
14100  SCIP_VAR* var;
14101  char filename[SCIP_MAXSTRLEN];
14102  int nvars;
14103  int v;
14104 
14105  /* open file */
14106  (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14107  file = fopen(filename, "w");
14108 
14109  /* check if the file was open */
14110  if( file == NULL )
14111  {
14112  SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14113  SCIPprintSysError(filename);
14114  return SCIP_FILECREATEERROR;
14115  }
14116 
14117  consdata = SCIPconsGetData(cons);
14118  assert(consdata != NULL);
14119 
14120  nvars = consdata->nvars;
14121 
14123  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
14124 
14125  /* create opening of the GML format */
14126  SCIPgmlWriteOpening(file, TRUE);
14127 
14128  for( v = 0; v < nvars; ++v )
14129  {
14130  char color[SCIP_MAXSTRLEN];
14131 
14132  var = consdata->vars[v];
14133  assert(var != NULL);
14134 
14135  SCIP_CALL( SCIPhashtableInsert(vars, (void*)var) );
14136 
14137  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14138  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14139  else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14140  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14141  else
14142  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14143 
14144  SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14145  }
14146 
14147  for( v = 0; v < nvars; ++v )
14148  {
14149  SCIP_VAR** vbdvars;
14150  int nvbdvars;
14151  int b;
14152 
14153  var = consdata->vars[v];
14154  assert(var != NULL);
14155 
14156  vbdvars = SCIPvarGetVlbVars(var);
14157  nvbdvars = SCIPvarGetNVlbs(var);
14158 
14159  for( b = 0; b < nvbdvars; ++b )
14160  {
14161  if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14162  {
14163  SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14164  }
14165  }
14166 
14167 #if 0
14168  vbdvars = SCIPvarGetVubVars(var);
14169  nvbdvars = SCIPvarGetNVubs(var);
14170 
14171  for( b = 0; b < nvbdvars; ++b )
14172  {
14173  if( SCIPhashtableExists(vars, vbdvars[b]) )
14174  {
14175  SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14176  }
14177  }
14178 #endif
14179  }
14180 
14181  /* create closing of the GML format */
14182  SCIPgmlWriteClosing(file);
14183 
14184  /* close file */
14185  fclose(file);
14186 
14187  SCIPhashtableFree(&vars);
14188 
14189  return SCIP_OKAY;
14190 }
14191 
14192 /** sets method to solve an individual cumulative condition */
14194  SCIP* scip, /**< SCIP data structure */
14195  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14196  )
14197 {
14198  SCIP_CONSHDLR* conshdlr;
14199  SCIP_CONSHDLRDATA* conshdlrdata;
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  return SCIP_PLUGINNOTFOUND;
14207  }
14208 
14209  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14210  assert(conshdlrdata != NULL);
14211 
14212  conshdlrdata->solveCumulative = solveCumulative;
14213 
14214  return SCIP_OKAY;
14215 }
14216 
14217 /** solves given cumulative condition as independent sub problem
14218  *
14219  * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14220  * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14221  * solver was interrupted.
14222  */
14224  SCIP* scip, /**< SCIP data structure */
14225  int njobs, /**< number of jobs (activities) */
14226  SCIP_Real* ests, /**< array with the earlier start time for each job */
14227  SCIP_Real* lsts, /**< array with the latest start time for each job */
14228  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14229  int* durations, /**< array of durations */
14230  int* demands, /**< array of demands */
14231  int capacity, /**< cumulative capacity */
14232  int hmin, /**< left bound of time axis to be considered (including hmin) */
14233  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14234  SCIP_Real timelimit, /**< time limit for solving in seconds */
14235  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14236  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14237  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14238  SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14239  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14240  SCIP_Bool* error /**< pointer to store if an error occurred */
14241  )
14242 {
14243  SCIP_CONSHDLR* conshdlr;
14244  SCIP_CONSHDLRDATA* conshdlrdata;
14245 
14246  (*solved) = TRUE;
14247  (*infeasible) = FALSE;
14248  (*unbounded) = FALSE;
14249  (*error) = FALSE;
14250 
14251  if( njobs == 0 )
14252  return SCIP_OKAY;
14253 
14254  /* find the cumulative constraint handler */
14255  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14256  if( conshdlr == NULL )
14257  {
14258  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14259  (*error) = TRUE;
14260  return SCIP_PLUGINNOTFOUND;
14261  }
14262 
14263  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14264  assert(conshdlrdata != NULL);
14265 
14266  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14267  if( timelimit > 0.0 && memorylimit > 10 )
14268  {
14269  SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14270  hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14271  }
14272 
14273  return SCIP_OKAY;
14274 }
14275 
14276 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14277  * completion time
14278  */
14280  SCIP* scip, /**< SCIP data structure */
14281  SCIP_PROFILE* profile, /**< resource profile */
14282  int nvars, /**< number of variables (jobs) */
14283  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14284  int* durations, /**< array containing corresponding durations */
14285  int* demands /**< array containing corresponding demands */
14286  )
14287 {
14288  SCIP_VAR* var;
14289  SCIP_HASHMAP* addedvars;
14290  int* copydemands;
14291  int* perm;
14292  int duration;
14293  int impliedest;
14294  int est;
14295  int impliedlct;
14296  int lct;
14297  int v;
14298 
14299  /* create hash map for variables which are added, mapping to their duration */
14300  SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), SCIPcalcHashtableSize(nvars)) );
14301 
14302  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14303  SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14304 
14305  /* sort variables w.r.t. job demands */
14306  for( v = 0; v < nvars; ++v )
14307  {
14308  copydemands[v] = demands[v];
14309  perm[v] = v;
14310  }
14311  SCIPsortDownIntInt(copydemands, perm, nvars);
14312 
14313  /* add each job with its earliest start and latest completion time into the resource profile */
14314  for( v = 0; v < nvars; ++v )
14315  {
14316  int idx;
14317 
14318  idx = perm[v];
14319  assert(idx >= 0 && idx < nvars);
14320 
14321  var = vars[idx];
14322  assert(var != NULL);
14323 
14324  duration = durations[idx];
14325  assert(duration > 0);
14326 
14327  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
14328  SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14329 
14330  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14331  SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14332 
14333  if( impliedest < impliedlct )
14334  {
14335  SCIP_Bool infeasible;
14336  int pos;
14337 
14338  SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14339  assert(!infeasible);
14340  assert(pos == -1);
14341  }
14342 
14343  if( est == impliedest && lct == impliedlct )
14344  {
14345  SCIP_CALL( SCIPhashmapInsert(addedvars, (void*)var, (void*)(size_t)duration) );
14346  }
14347  }
14348 
14349  SCIPfreeBufferArray(scip, &copydemands);
14350  SCIPfreeBufferArray(scip, &perm);
14351 
14352  SCIPhashmapFree(&addedvars);
14353 
14354  return SCIP_OKAY;
14355 }
14356 
14357 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */
14358 int SCIPcomputeHmin(
14359  SCIP* scip, /**< SCIP data structure */
14360  SCIP_PROFILE* profile, /**< worst case resource profile */
14361  int capacity /**< capacity to check */
14362  )
14363 {
14364  int* timepoints;
14365  int* loads;
14366  int ntimepoints;
14367  int t;
14368 
14369  ntimepoints = SCIPprofileGetNTimepoints(profile);
14370  timepoints = SCIPprofileGetTimepoints(profile);
14371  loads = SCIPprofileGetLoads(profile);
14372 
14373  /* find first time point which potentially violates the capacity restriction */
14374  for( t = 0; t < ntimepoints - 1; ++t )
14375  {
14376  /* check if the time point exceed w.r.t. worst case profile the capacity */
14377  if( loads[t] > capacity )
14378  {
14379  assert(t == 0 || loads[t-1] <= capacity);
14380  return timepoints[t];
14381  }
14382  }
14383 
14384  return INT_MAX;
14385 }
14386 
14387 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity is satisfied for sure */
14388 int SCIPcomputeHmax(
14389  SCIP* scip, /**< SCIP data structure */
14390  SCIP_PROFILE* profile, /**< worst case profile */
14391  int capacity /**< capacity to check */
14392  )
14393 {
14394  int* timepoints;
14395  int* loads;
14396  int ntimepoints;
14397  int t;
14398 
14399  ntimepoints = SCIPprofileGetNTimepoints(profile);
14400  timepoints = SCIPprofileGetTimepoints(profile);
14401  loads = SCIPprofileGetLoads(profile);
14402 
14403  /* find last time point which potentially violates the capacity restriction */
14404  for( t = ntimepoints - 1; t >= 0; --t )
14405  {
14406  /* check if at time point t the worst case resource profile exceeds the capacity */
14407  if( loads[t] > capacity )
14408  {
14409  assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14410  return timepoints[t+1];
14411  }
14412  }
14413 
14414  return INT_MIN;
14415 }
14416 
14417 /**@} */
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:22777
SCIP_RETCODE SCIPbtnodeCreate(SCIP_BT *tree, SCIP_BTNODE **node, void *dataptr)
Definition: misc.c:6639
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41572
#define CONSHDLR_SEPAPRIORITY
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
SCIP_RETCODE SCIPsetSolveCumulative(SCIP *scip, SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)))
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:41685
void SCIPbtnodeFree(SCIP_BT *tree, SCIP_BTNODE **node)
Definition: misc.c:6703
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip.c:28308
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:10698
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:5878
#define SCIPallocMemory(scip, ptr)
Definition: scip.h:20526
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:5588
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:25588
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:16443
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:908
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:22886
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)
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:20589
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:41648
int SCIPconvertRealToInt(SCIP *scip, SCIP_Real real)
Definition: scip.c:42415
SCIP_RETCODE SCIPprofileDeleteCore(SCIP_PROFILE *profile, int left, int right, int demand)
Definition: misc.c:5268
static SCIP_RETCODE computeMinDistance(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int source, int sink, int *naddconss)
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip.c:15468
void * SCIPbtnodeGetData(SCIP_BTNODE *node)
Definition: misc.c:6748
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:1567
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20573
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:10378
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:11540
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:15737
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:4154
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip.c:10653
static void addEndingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *endtimes, int *endindices, int *freecapacity, int *idx, int nvars)
#define SCIP_MAXSTRLEN
Definition: def.h:201
#define DEFAULT_MAXNODES
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip.c:5634
SCIP_RETCODE SCIPtransformConss(SCIP *scip, int nconss, SCIP_CONS **conss, SCIP_CONS **transconss)
Definition: scip.c:25401
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:5246
void SCIPgmlWriteArc(FILE *file, unsigned int source, unsigned int target, const char *label, const char *color)
Definition: misc.c:437
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:130
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:17113
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1125
#define CONSHDLR_NAME
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17323
#define CONSHDLR_PROP_TIMING
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:7849
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17261
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:7681
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:5334
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17067
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:295
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:5065
static SCIP_RETCODE computePeak(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *timepoint)
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17291
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:24320
#define SCIPfreeMemoryArray(scip, ptr)
Definition: scip.h:20544
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip.c:17429
void SCIPgmlWriteClosing(FILE *file)
Definition: misc.c:497
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:5818
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:7842
void SCIPbtnodeSetRightchild(SCIP_BTNODE *node, SCIP_BTNODE *right)
Definition: misc.c:6909
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)
#define SCIPallocMemoryArray(scip, ptr, num)
Definition: scip.h:20528
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:15817
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:7909
#define FALSE
Definition: def.h:56
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:2057
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip.c:41009
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip.c:4046
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:7778
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:8174
#define TRUE
Definition: def.h:55
SCIP_RETCODE SCIPvisualizeConsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:7640
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip.c:33396
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
int SCIPgetNVarsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
enum Proprule PROPRULE
static void subtractStartingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *starttimes, int *startindices, int *freecapacity, int *idx, int nvars)
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:5795
#define SCIP_CALL(x)
Definition: def.h:266
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)
static SCIP_RETCODE presolveCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nfixedvars, int *nchgbds, int *ndelconss, int *naddconss, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition: scip.c:4109
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 strengthenVarbounds(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *naddconss)
SCIP_Bool SCIPallowDualReds(SCIP *scip)
Definition: scip.c:23083
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:42008
#define DEFAULT_LOCALCUTS
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20556
SCIP_Real SCIPvarGetLbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:15737
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:5238
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:3601
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:34983
#define CONSHDLR_DELAYPROP
static SCIP_RETCODE separateCoverCutsCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
#define DEFAULT_USEBINVARS
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:85
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:16905
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:24914
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:2116
#define DEFAULT_COEFTIGHTENING
static SCIP_RETCODE createNodedata(SCIP *scip, SCIP_NODEDATA **nodedata)
#define SCIP_LONGINT_MAX
Definition: def.h:113
SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_setppc.c:9063
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:7839
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:7779
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:26237
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:30967
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:24949
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)
int SCIPprofileGetLoad(SCIP_PROFILE *profile, int pos)
Definition: misc.c:5077
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:20554
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11206
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
Definition: scip.c:42044
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
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
static SCIP_RETCODE deleteTrivilCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:5359
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:7769
SCIP_Bool SCIPbtnodeIsRoot(SCIP_BTNODE *node)
Definition: misc.c:6808
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:20572
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:1480
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:24720
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:3547
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16562
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2159
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip.c:16156
SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
Definition: scip.c:9077
int SCIPcomputeHmax(SCIP *scip, SCIP_PROFILE *profile, int capacity)
static SCIP_RETCODE updateEnvelop(SCIP *scip, SCIP_BTNODE *node)
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:3917
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:36622
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 .
#define SCIPfreeMemory(scip, ptr)
Definition: scip.h:20542
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip)
Definition: scip.c:24342
int SCIPgetNConss(SCIP *scip)
Definition: scip.c:11736
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41585
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16585
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:1781
int * SCIPgetValsLinking(SCIP *scip, SCIP_CONS *cons)
#define CONSHDLR_EAGERFREQ
#define CONSHDLR_PRESOLTIMING
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
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:17303
static int inferInfoGetData2(INFERINFO inferinfo)
#define EVENTHDLR_NAME
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:41709
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:7879
static SCIP_DECL_CONSLOCK(consLockCumulative)
SCIP_BTNODE * SCIPbtnodeGetParent(SCIP_BTNODE *node)
Definition: misc.c:6758
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
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:19526
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:20574
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip.c:25300
void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:41996
void SCIPbtnodeSetLeftchild(SCIP_BTNODE *node, SCIP_BTNODE *left)
Definition: misc.c:6895
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:3897
int SCIPcalcHashtableSize(int minsize)
Definition: misc.c:1157
SCIP_Real SCIPvarGetUbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:15859
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:16644
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41598
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:5527
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:28151
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:41353
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:8275
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:7620
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:16654
static SCIP_RETCODE computeEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss, int *nchgsides)
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
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:41907
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:19126
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:146
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2075
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:5503
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:20562
static SCIP_RETCODE propagateCumulativeCondition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *redundant, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetHminCumulative(SCIP *scip, SCIP_CONS *cons, int hmin)
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:3204
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:41637
static int computeTotalEnergy(int *durations, int *demands, int njobs)
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
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)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip.c:5292
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:50
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:5192
void SCIPsortDownIntIntInt(int *intarray1, int *intarray2, int *intarray3, int len)
#define SCIPstatisticPrintf
Definition: pub_message.h:107
SCIP_RETCODE SCIPpropCumulativeCondition(SCIP *scip, SCIP_PRESOLTIMING presoltiming, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip.c:766
static TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
SCIP_RETCODE SCIPprofileCreate(SCIP_PROFILE **profile, int capacity)
Definition: misc.c:4965
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:32131
#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:6846
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:50
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip.h:20598
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:97
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:7650
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:16884
static SCIP_RETCODE consCapacityConstraintsFinder(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
SCIP_BTNODE * SCIPbtGetRoot(SCIP_BT *tree)
Definition: misc.c:7031
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:12080
static SCIP_RETCODE consCheckRedundancy(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *redundant)
SCIP_RETCODE 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:17116
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41611
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:23119
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:20193
SCIP_BTNODE * SCIPbtnodeGetRightchild(SCIP_BTNODE *node)
Definition: misc.c:6778
#define SCIP_UNKNOWN
Definition: def.h:148
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17123
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip.c:997
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:5479
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:24772
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip.c:25097
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:16740
#define SCIP_Bool
Definition: def.h:53
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:4001
#define DEFAULT_DUALPRESOLVE
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip.c:1216
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
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nchgbds, int *ndelconss, SCIP_Bool *cutoff)
void SCIPprintSysError(const char *message)
Definition: misc.c:8110
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17313
SCIP_VAR ** SCIPgetVarsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:801
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:7859
#define DEFAULT_USECOVERCUTS
static void freeNodedata(SCIP *scip, SCIP_NODEDATA **nodedata)
SCIP_Bool SCIPprofileFindLeft(SCIP_PROFILE *profile, int timepoint, int *pos)
Definition: misc.c:5091
static SCIP_DECL_EVENTEXEC(eventExecCumulative)
SCIP_RETCODE SCIPsetSubscipsOff(SCIP *scip, SCIP_Bool quiet)
Definition: scip.c:4382
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:27811
#define SCIP_DECL_CONSEXITPRE(x)
Definition: type_cons.h:138
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:8245
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
Definition: scip.c:24369
static SCIP_RETCODE normalizeDemands(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17281
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:6939
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:7869
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:7739
SCIP_Bool SCIPbtnodeIsLeftchild(SCIP_BTNODE *node)
Definition: misc.c:6828
SCIP_RETCODE SCIPcreateConsBasicSetpart(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
Definition: cons_setppc.c:8930
SCIP_Longint SCIPgetMemUsed(SCIP *scip)
Definition: scip.c:41396
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:21563
SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
Definition: scip.c:24403
#define SCIP_PRESOLTIMING_ALWAYS
Definition: type_timing.h:48
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:5611
int SCIPgetNRuns(SCIP *scip)
Definition: scip.c:37318
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17249
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:89
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:5003
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)
#define SCIPstatistic(x)
Definition: pub_message.h:101
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:5045
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:38140
#define DEFAULT_FILLBRANCHCANDS
static SCIP_Bool checkDemands(SCIP *scip, SCIP_CONS *cons)
int * SCIPprofileGetLoads(SCIP_PROFILE *profile)
Definition: misc.c:5055
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41624
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:1510
SCIP_Bool SCIPbtIsEmpty(SCIP_BT *tree)
Definition: misc.c:7021
#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:20469
static SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
SCIP_BTNODE * SCIPbtnodeGetLeftchild(SCIP_BTNODE *node)
Definition: misc.c:6768
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:36668
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:5565
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:11477
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip.c:14503
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:16608
SCIP_RETCODE SCIPincludeConshdlrCumulative(SCIP *scip)
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17271
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:20585
void SCIPbtSetRoot(SCIP_BT *tree, SCIP_BTNODE *root)
Definition: misc.c:7044
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17057
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2177
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip.c:692
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:6881
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:5772
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:3829
SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
Definition: scip.c:33775
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:27834
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:25072
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:1281
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:11878
#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:20593
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:5455
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:19453
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:16750
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)
static SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
#define SCIP_Real
Definition: def.h:127
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:7799
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip.c:25047
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:24635
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:20299
static SCIP_DECL_CONSTRANS(consTransCumulative)
#define MIN(x, y)
Definition: memory.c:67
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:27600
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:28334
#define DEFAULT_EFCHECK
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:20568
#define SCIP_INVALID
Definition: def.h:147
#define EVENTHDLR_DESC
#define SCIPfreeBuffer(scip, ptr)
Definition: scip.h:20595
#define DEFAULT_TTEFINFER
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:27738
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:24471
#define SCIP_Longint
Definition: def.h:112
static SCIP_RETCODE detectRedundantConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, int *naddconss)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:20571
SCIP_RETCODE SCIPsetEmphasis(SCIP *scip, SCIP_PARAMEMPHASIS paramemphasis, SCIP_Bool quiet)
Definition: scip.c:4360
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:1692
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:19399
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition: scip.c:3938
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:49
static SCIP_RETCODE separateConsOnIntegerVariables(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool lower, SCIP_Bool *separated)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:20597
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16730
static void consdataCalcSignature(SCIP_CONSDATA *consdata)
#define DEFAULT_EFINFER
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip.c:3797
static SCIP_RETCODE createCapacityRestriction(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool cutsasconss)
#define SCIPdebug(x)
Definition: pub_message.h:74
void SCIPgmlWriteOpening(FILE *file, SCIP_Bool directed)
Definition: misc.c:481
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:24436
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:41422
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2094
#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:7829
SCIP_RETCODE SCIPbtCreate(SCIP_BT **tree, BMS_BLKMEM *blkmem)
Definition: misc.c:6920
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:24659
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:41697
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:35767
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:5035
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:5841
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:27864
#define SCIPABORT()
Definition: def.h:238
static SCIP_DECL_CONSDELETE(consDeleteCumulative)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:7789
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:7083
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:7819
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:3927
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3149
SCIP_Bool SCIPbtnodeIsLeaf(SCIP_BTNODE *node)
Definition: misc.c:6818
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip.c:36834
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:4989
#define CONSHDLR_ENFOPRIORITY
static SCIP_Bool impliesVubPrecedenceCondition(SCIP *scip, SCIP_VAR *var, SCIP_Real vubcoef, SCIP_Real vubconst, int duration)
#define SCIPallocBuffer(scip, ptr)
Definition: scip.h:20583
SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
Definition: scip.c:41409
#define DEFAULT_SEPAOLD
SCIP_RETCODE SCIPnormalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)