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-2021 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_cumulative.c
17  * @ingroup DEFPLUGINS_CONS
18  * @brief constraint handler for cumulative constraints
19  * @author Timo Berthold
20  * @author Stefan Heinz
21  * @author Jens Schulz
22  *
23  * Given:
24  * - a set of jobs, represented by their integer start time variables \f$S_j\f$, their array of processing times \f$p_j\f$ and of
25  * their demands \f$d_j\f$.
26  * - an integer resource capacity \f$C\f$
27  *
28  * The cumulative constraint ensures that for each point in time \f$t\f$ \f$\sum_{j: S_j \leq t < S_j + p_j} d_j \leq C\f$ holds.
29  *
30  * Separation:
31  * - can be done using binary start time model, see Pritskers, Watters and Wolfe
32  * - or by just separating relatively weak cuts on the integer start time variables
33  *
34  * Propagation:
35  * - time tabling, Klein & Scholl (1999)
36  * - Edge-finding from Petr Vilim, adjusted and simplified for dynamic repropagation
37  * (2009)
38  * - energetic reasoning, see Baptiste, Le Pape, Nuijten (2001)
39  *
40  */
41 
42 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
43 
44 #include <assert.h>
45 #include <string.h>
46 
47 #include "tclique/tclique.h"
48 #include "scip/cons_cumulative.h"
49 #include "scip/cons_linking.h"
50 #include "scip/cons_knapsack.h"
51 #include "scip/scipdefplugins.h"
52 
53 /**@name Constraint handler properties
54  *
55  * @{
56  */
57 
58 /* constraint handler properties */
59 #define CONSHDLR_NAME "cumulative"
60 #define CONSHDLR_DESC "cumulative constraint handler"
61 #define CONSHDLR_SEPAPRIORITY 2100000 /**< priority of the constraint handler for separation */
62 #define CONSHDLR_ENFOPRIORITY -2040000 /**< priority of the constraint handler for constraint enforcing */
63 #define CONSHDLR_CHECKPRIORITY -3030000 /**< priority of the constraint handler for checking feasibility */
64 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
65 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
66 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
67  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
68 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
69 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
70 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
71 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
72 
73 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
74 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
75 
76 /**@} */
77 
78 /**@name Default parameter values
79  *
80  * @{
81  */
82 
83 /* default parameter values */
84 
85 /* separation */
86 #define DEFAULT_USEBINVARS FALSE /**< should the binary representation be used? */
87 #define DEFAULT_LOCALCUTS FALSE /**< should cuts be added only locally? */
88 #define DEFAULT_USECOVERCUTS TRUE /**< should covering cuts be added? */
89 #define DEFAULT_CUTSASCONSS TRUE /**< should the cuts be created as knapsack constraints? */
90 #define DEFAULT_SEPAOLD TRUE /**< shall old sepa algo be applied? */
91 
92 /* propagation */
93 #define DEFAULT_TTINFER TRUE /**< should time-table (core-times) propagator be used to infer bounds? */
94 #define DEFAULT_EFCHECK FALSE /**< should edge-finding be used to detect an overload? */
95 #define DEFAULT_EFINFER FALSE /**< should edge-finding be used to infer bounds? */
96 #define DEFAULT_USEADJUSTEDJOBS FALSE /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
97 #define DEFAULT_TTEFCHECK TRUE /**< should time-table edge-finding be used to detect an overload? */
98 #define DEFAULT_TTEFINFER TRUE /**< should time-table edge-finding be used to infer bounds? */
99 
100 /* presolving */
101 #define DEFAULT_DUALPRESOLVE TRUE /**< should dual presolving be applied? */
102 #define DEFAULT_COEFTIGHTENING FALSE /**< should coeffisient tightening be applied? */
103 #define DEFAULT_NORMALIZE TRUE /**< should demands and capacity be normalized? */
104 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
105 #define DEFAULT_DISJUNCTIVE TRUE /**< extract disjunctive constraints? */
106 #define DEFAULT_DETECTDISJUNCTIVE TRUE /**< search for conflict set via maximal cliques to detect disjunctive constraints */
107 #define DEFAULT_DETECTVARBOUNDS TRUE /**< search for conflict set via maximal cliques to detect variable bound constraints */
108 #define DEFAULT_MAXNODES 10000LL /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
110 /* enforcement */
111 #define DEFAULT_FILLBRANCHCANDS FALSE /**< should branching candidates be added to storage? */
113 /* conflict analysis */
114 #define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used during conflict analysis? */
116 /**@} */
117 
118 /**@name Event handler properties
119  *
120  * @{
121  */
122 
123 #define EVENTHDLR_NAME "cumulative"
124 #define EVENTHDLR_DESC "bound change event handler for cumulative constraints"
126 /**@} */
127 
128 /*
129  * Data structures
130  */
131 
132 /** constraint data for cumulative constraints */
133 struct SCIP_ConsData
134 {
135  SCIP_VAR** vars; /**< array of variable representing the start time of each job */
136  SCIP_Bool* downlocks; /**< array to store if the variable has a down lock */
137  SCIP_Bool* uplocks; /**< array to store if the variable has an uplock */
138  SCIP_CONS** linkingconss; /**< array of linking constraints for the integer variables */
139  SCIP_ROW** demandrows; /**< array of rows of linear relaxation of this problem */
140  SCIP_ROW** scoverrows; /**< array of rows of small cover cuts of this problem */
141  SCIP_ROW** bcoverrows; /**< array of rows of big cover cuts of this problem */
142  int* demands; /**< array containing corresponding demands */
143  int* durations; /**< array containing corresponding durations */
144  SCIP_Real resstrength1; /**< stores the resource strength 1*/
145  SCIP_Real resstrength2; /**< stores the resource strength 2 */
146  SCIP_Real cumfactor1; /**< stroes the cumulativeness of the constraint */
147  SCIP_Real disjfactor1; /**< stores the disjunctiveness of the constraint */
148  SCIP_Real disjfactor2; /**< stores the disjunctiveness of the constraint */
149  SCIP_Real estimatedstrength;
150  int nvars; /**< number of variables */
151  int varssize; /**< size of the arrays */
152  int ndemandrows; /**< number of rows of cumulative constrint for linear relaxation */
153  int demandrowssize; /**< size of array rows of demand rows */
154  int nscoverrows; /**< number of rows of small cover cuts */
155  int scoverrowssize; /**< size of array of small cover cuts */
156  int nbcoverrows; /**< number of rows of big cover cuts */
157  int bcoverrowssize; /**< size of array of big cover cuts */
158  int capacity; /**< available cumulative capacity */
159 
160  int hmin; /**< left bound of time axis to be considered (including hmin) */
161  int hmax; /**< right bound of time axis to be considered (not including hmax) */
162 
163  unsigned int signature; /**< constraint signature which is need for pairwise comparison */
164 
165  unsigned int validsignature:1; /**< is the signature valid */
166  unsigned int normalized:1; /**< is the constraint normalized */
167  unsigned int covercuts:1; /**< cover cuts are created? */
168  unsigned int propagated:1; /**< is constraint propagted */
169  unsigned int varbounds:1; /**< bool to store if variable bound strengthening was already preformed */
170  unsigned int triedsolving:1; /**< bool to store if we tried already to solve that constraint as independent subproblem */
171 
172 #ifdef SCIP_STATISTIC
173  int maxpeak;
174 #endif
175 };
176 
177 /** constraint handler data */
178 struct SCIP_ConshdlrData
179 {
180  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
181 
182  SCIP_Bool usebinvars; /**< should the binary variables be used? */
183  SCIP_Bool cutsasconss; /**< should the cumulative constraint create cuts as knapsack constraints? */
184  SCIP_Bool ttinfer; /**< should time-table (core-times) propagator be used to infer bounds? */
185  SCIP_Bool efcheck; /**< should edge-finding be used to detect an overload? */
186  SCIP_Bool efinfer; /**< should edge-finding be used to infer bounds? */
187  SCIP_Bool useadjustedjobs; /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
188  SCIP_Bool ttefcheck; /**< should time-table edge-finding be used to detect an overload? */
189  SCIP_Bool ttefinfer; /**< should time-table edge-finding be used to infer bounds? */
190  SCIP_Bool localcuts; /**< should cuts be added only locally? */
191  SCIP_Bool usecovercuts; /**< should covering cuts be added? */
192  SCIP_Bool sepaold; /**< shall old sepa algo be applied? */
193 
194  SCIP_Bool fillbranchcands; /**< should branching candidates be added to storage? */
195 
196  SCIP_Bool dualpresolve; /**< should dual presolving be applied? */
197  SCIP_Bool coeftightening; /**< should coeffisient tightening be applied? */
198  SCIP_Bool normalize; /**< should demands and capacity be normalized? */
199  SCIP_Bool disjunctive; /**< extract disjunctive constraints? */
200  SCIP_Bool detectdisjunctive; /**< search for conflict set via maximal cliques to detect disjunctive constraints */
201  SCIP_Bool detectvarbounds; /**< search for conflict set via maximal cliques to detect variable bound constraints */
202  SCIP_Bool usebdwidening; /**< should bound widening be used during conflict analysis? */
203  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
204  SCIP_Bool detectedredundant; /**< was detection of redundant constraints already performed? */
205 
206  SCIP_Longint maxnodes; /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
207 
208  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)); /**< method to use a single cumulative condition */
209 
210  /* statistic values which are collected if SCIP_STATISTIC is defined */
211 #ifdef SCIP_STATISTIC
212  SCIP_Longint nlbtimetable; /**< number of times the lower bound was tightened by the time-table propagator */
213  SCIP_Longint nubtimetable; /**< number of times the upper bound was tightened by the time-table propagator */
214  SCIP_Longint ncutofftimetable; /**< number of times the a cutoff was detected due to time-table propagator */
215  SCIP_Longint nlbedgefinder; /**< number of times the lower bound was tightened by the edge-finder propagator */
216  SCIP_Longint nubedgefinder; /**< number of times the upper bound was tightened by the edge-finder propagator */
217  SCIP_Longint ncutoffedgefinder; /**< number of times the a cutoff was detected due to edge-finder propagator */
218  SCIP_Longint ncutoffoverload; /**< number of times the a cutoff was detected due to overload checking via edge-finding */
219  SCIP_Longint nlbTTEF; /**< number of times the lower bound was tightened by time-table edge-finding */
220  SCIP_Longint nubTTEF; /**< number of times the upper bound was tightened by time-table edge-finding */
221  SCIP_Longint ncutoffoverloadTTEF;/**< number of times the a cutoff was detected due to overload checking via time-table edge-finding */
222 
223  int nirrelevantjobs; /**< number of time a irrelevant/redundant jobs was removed form a constraint */
224  int nalwaysruns; /**< number of time a job removed form a constraint which run completely during the effective horizon */
225  int nremovedlocks; /**< number of times a up or down lock was removed */
226  int ndualfixs; /**< number of times a dual fix was performed by a single constraint */
227  int ndecomps; /**< number of times a constraint was decomposed */
228  int ndualbranchs; /**< number of times a dual branch was discoverd and applicable via probing */
229  int nallconsdualfixs; /**< number of times a dual fix was performed due to knowledge of all cumulative constraints */
230  int naddedvarbounds; /**< number of added variable bounds constraints */
231  int naddeddisjunctives; /**< number of added disjunctive constraints */
232 
233  SCIP_Bool iscopy; /**< Boolean to store if constraint handler is part of a copy */
234 #endif
235 };
236 
237 /**@name Inference Information Methods
238  *
239  * An inference information can be passed with each domain reduction to SCIP. This information is passed back to the
240  * constraint handler if the corresponding bound change has to be explained. It can be used to store information which
241  * help to construct a reason/explanation for a bound change. The inference information is limited to size of integer.
242  *
243  * In case of the cumulative constraint handler we store the used propagation algorithms for that particular bound
244  * change and the earliest start and latest completion time of all jobs in the conflict set.
245  *
246  * @{
247  */
248 
249 /** Propagation rules */
250 enum Proprule
251 {
252  PROPRULE_0_INVALID = 0, /**< invalid inference information */
253  PROPRULE_1_CORETIMES = 1, /**< core-time propagator */
254  PROPRULE_2_EDGEFINDING = 2, /**< edge-finder */
255  PROPRULE_3_TTEF = 3 /**< time-table edeg-finding */
256 };
257 typedef enum Proprule PROPRULE;
259 /** inference information */
260 struct InferInfo
261 {
262  union
263  {
264  /** struct to use the inference information */
265  struct
266  {
267  unsigned int proprule:2; /**< propagation rule that was applied */
268  unsigned int data1:15; /**< data field one */
269  unsigned int data2:15; /**< data field two */
270  } asbits;
271  int asint; /**< inference information as a single int value */
272  } val;
273 };
274 typedef struct InferInfo INFERINFO;
276 /** converts an integer into an inference information */
277 static
278 INFERINFO intToInferInfo(
279  int i /**< integer to convert */
280  )
281 {
282  INFERINFO inferinfo;
283 
284  inferinfo.val.asint = i;
285 
286  return inferinfo;
287 }
288 
289 /** converts an inference information into an int */
290 static
291 int inferInfoToInt(
292  INFERINFO inferinfo /**< inference information to convert */
293  )
294 {
295  return inferinfo.val.asint;
296 }
297 
298 /** returns the propagation rule stored in the inference information */
299 static
301  INFERINFO inferinfo /**< inference information to convert */
302  )
303 {
304  return (PROPRULE) inferinfo.val.asbits.proprule;
305 }
306 
307 /** returns data field one of the inference information */
308 static
310  INFERINFO inferinfo /**< inference information to convert */
311  )
312 {
313  return (int) inferinfo.val.asbits.data1;
314 }
315 
316 /** returns data field two of the inference information */
317 static
319  INFERINFO inferinfo /**< inference information to convert */
320  )
321 {
322  return (int) inferinfo.val.asbits.data2;
323 }
324 
325 /** returns whether the inference information is valid */
326 static
328  INFERINFO inferinfo /**< inference information to convert */
329  )
330 {
331  return (inferinfo.val.asint != 0);
332 }
333 
334 
335 /** constructs an inference information out of a propagation rule, an earliest start and a latest completion time */
336 static
337 INFERINFO getInferInfo(
338  PROPRULE proprule, /**< propagation rule that deduced the value */
339  int data1, /**< data field one */
340  int data2 /**< data field two */
341  )
342 {
343  INFERINFO inferinfo;
344 
345  /* check that the data members are in the range of the available bits */
346  if( proprule == PROPRULE_0_INVALID || data1 < 0 || data1 >= (1<<15) || data2 < 0 || data2 >= (1<<15) )
347  {
348  inferinfo.val.asint = 0;
349  assert(inferInfoGetProprule(inferinfo) == PROPRULE_0_INVALID);
350  assert(inferInfoIsValid(inferinfo) == FALSE);
351  }
352  else
353  {
354  inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
355  inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
356  inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
357  assert(inferInfoIsValid(inferinfo) == TRUE);
358  }
359 
360  return inferinfo;
361 }
362 
363 /**@} */
364 
365 /*
366  * Local methods
367  */
368 
369 /**@name Miscellaneous Methods
370  *
371  * @{
372  */
373 
374 #ifndef NDEBUG
375 
376 /** compute the core of a job which lies in certain interval [begin, end) */
377 static
379  int begin, /**< begin of the interval */
380  int end, /**< end of the interval */
381  int ect, /**< earliest completion time */
382  int lst /**< latest start time */
383  )
384 {
385  int core;
386 
387  core = MAX(0, MIN(end, ect) - MAX(lst, begin));
388 
389  return core;
390 }
391 #else
392 #define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
393 #endif
394 
395 /** returns the implied earliest start time */ /*lint -e{715}*/
396 static
398  SCIP* scip, /**< SCIP data structure */
399  SCIP_VAR* var, /**< variable for which the implied est should be returned */
400  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
401  int* est /**< pointer to store the implied earliest start time */
402  )
403 { /*lint --e{715}*/
404 #if 0
405  SCIP_VAR** vbdvars;
406  SCIP_VAR* vbdvar;
407  SCIP_Real* vbdcoefs;
408  SCIP_Real* vbdconsts;
409  void* image;
410  int nvbdvars;
411  int v;
412 #endif
413 
414  (*est) = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
415 
416 #if 0
417  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
418 
419  nvbdvars = SCIPvarGetNVlbs(var);
420  vbdvars = SCIPvarGetVlbVars(var);
421  vbdcoefs = SCIPvarGetVlbCoefs(var);
422  vbdconsts = SCIPvarGetVlbConstants(var);
423 
424  for( v = 0; v < nvbdvars; ++v )
425  {
426  vbdvar = vbdvars[v];
427  assert(vbdvar != NULL);
428 
429  image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
430 
431  if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
432  {
433  int duration;
434  int vbdconst;
435 
436  duration = (int)(size_t)image;
437  vbdconst = SCIPconvertRealToInt(scip, vbdconsts[v]);
438 
439  SCIPdebugMsg(scip, "check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
441  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
442 
443  if( duration >= vbdconst )
444  {
445  int impliedest;
446 
447  impliedest = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
448 
449  if( (*est) < impliedest )
450  {
451  (*est) = impliedest;
452 
453  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
454  }
455  }
456  }
457  }
458 #endif
459 
460  return SCIP_OKAY;
461 }
462 
463 /** returns the implied latest completion time */ /*lint -e{715}*/
464 static
466  SCIP* scip, /**< SCIP data structure */
467  SCIP_VAR* var, /**< variable for which the implied est should be returned */
468  int duration, /**< duration of the given job */
469  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
470  int* lct /**< pointer to store the implied latest completion time */
471  )
472 { /*lint --e{715}*/
473 #if 0
474  SCIP_VAR** vbdvars;
475  SCIP_VAR* vbdvar;
476  SCIP_Real* vbdcoefs;
477  SCIP_Real* vbdconsts;
478  int nvbdvars;
479  int v;
480 #endif
481 
482  (*lct) = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
483 
484 #if 0
485  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
486 
487  nvbdvars = SCIPvarGetNVubs(var);
488  vbdvars = SCIPvarGetVubVars(var);
489  vbdcoefs = SCIPvarGetVubCoefs(var);
490  vbdconsts = SCIPvarGetVubConstants(var);
491 
492  for( v = 0; v < nvbdvars; ++v )
493  {
494  vbdvar = vbdvars[v];
495  assert(vbdvar != NULL);
496 
497  if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
498  {
499  int vbdconst;
500 
501  vbdconst = SCIPconvertRealToInt(scip, -vbdconsts[v]);
502 
503  SCIPdebugMsg(scip, "check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
505  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
506 
507  if( duration >= -vbdconst )
508  {
509  int impliedlct;
510 
511  impliedlct = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
512 
513  if( (*lct) > impliedlct )
514  {
515  (*lct) = impliedlct;
516 
517  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
518  }
519  }
520  }
521  }
522 #endif
523 
524  return SCIP_OKAY;
525 }
526 
527 /** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
528 static
530  SCIP* scip, /**< SCIP data structure */
531  SCIP_CONSDATA* consdata, /**< constraint data */
532  SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
533  int** coefs, /**< pointer to store the coefficients */
534  int* nvars, /**< number if collect binary variables */
535  int* startindices, /**< permutation with rspect to the start times */
536  int curtime, /**< current point in time */
537  int nstarted, /**< number of jobs that start before the curtime or at curtime */
538  int nfinished /**< number of jobs that finished before curtime or at curtime */
539  )
540 {
541  int nrowvars;
542  int startindex;
543  int size;
544 
545  size = 10;
546  nrowvars = 0;
547  startindex = nstarted - 1;
548 
549  SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
550  SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
551 
552  /* search for the (nstarted - nfinished) jobs which are active at curtime */
553  while( nstarted - nfinished > nrowvars )
554  {
555  SCIP_VAR* var;
556  int endtime;
557  int duration;
558  int demand;
559  int varidx;
560 
561  /* collect job information */
562  varidx = startindices[startindex];
563  assert(varidx >= 0 && varidx < consdata->nvars);
564 
565  var = consdata->vars[varidx];
566  duration = consdata->durations[varidx];
567  demand = consdata->demands[varidx];
568  assert(var != NULL);
569 
570  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
571 
572  /* check the end time of this job is larger than the curtime; in this case the job is still running */
573  if( endtime > curtime )
574  {
575  SCIP_VAR** binvars;
576  SCIP_Real* vals;
577  int nbinvars;
578  int start;
579  int end;
580  int b;
581 
582  /* check if the linking constraints exists */
583  assert(SCIPexistsConsLinking(scip, var));
584  assert(SCIPgetConsLinking(scip, var) != NULL);
585  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
586 
587  /* collect linking constraint information */
588  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
589  vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
590 
591  start = curtime - duration + 1;
592  end = MIN(curtime, endtime - duration);
593 
594  for( b = 0; b < nbinvars; ++b )
595  {
596  if( vals[b] < start )
597  continue;
598 
599  if( vals[b] > end )
600  break;
601 
602  assert(binvars[b] != NULL);
603 
604  /* ensure array proper array size */
605  if( size == *nvars )
606  {
607  size *= 2;
608  SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
609  SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
610  }
611 
612  (*vars)[*nvars] = binvars[b];
613  (*coefs)[*nvars] = demand;
614  (*nvars)++;
615  }
616  nrowvars++;
617  }
618 
619  startindex--;
620  }
621 
622  return SCIP_OKAY;
623 }
624 
625 /** collect all integer variable which belong to jobs which can run at the point of interest */
626 static
628  SCIP* scip, /**< SCIP data structure */
629  SCIP_CONSDATA* consdata, /**< constraint data */
630  SCIP_VAR*** activevars, /**< jobs that are currently running */
631  int* startindices, /**< permutation with rspect to the start times */
632  int curtime, /**< current point in time */
633  int nstarted, /**< number of jobs that start before the curtime or at curtime */
634  int nfinished, /**< number of jobs that finished before curtime or at curtime */
635  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
636  int* lhs /**< lhs for the new row sum of lbs + minoffset */
637  )
638 {
639  SCIP_VAR* var;
640  int startindex;
641  int endtime;
642  int duration;
643  int starttime;
644 
645  int varidx;
646  int sumofstarts;
647  int mindelta;
648  int counter;
649 
650  assert(curtime >= consdata->hmin);
651  assert(curtime < consdata->hmax);
652 
653  counter = 0;
654  sumofstarts = 0;
655 
656  mindelta = INT_MAX;
657 
658  startindex = nstarted - 1;
659 
660  /* search for the (nstarted - nfinished) jobs which are active at curtime */
661  while( nstarted - nfinished > counter )
662  {
663  assert(startindex >= 0);
664 
665  /* collect job information */
666  varidx = startindices[startindex];
667  assert(varidx >= 0 && varidx < consdata->nvars);
668 
669  var = consdata->vars[varidx];
670  duration = consdata->durations[varidx];
671  assert(duration > 0);
672  assert(var != NULL);
673 
674  if( lower )
675  starttime = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
676  else
677  starttime = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
678 
679  endtime = MIN(starttime + duration, consdata->hmax);
680 
681  /* check the end time of this job is larger than the curtime; in this case the job is still running */
682  if( endtime > curtime )
683  {
684  (*activevars)[counter] = var;
685  sumofstarts += starttime;
686  mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
687  counter++;
688  }
689 
690  startindex--;
691  }
692 
693  assert(mindelta > 0);
694  *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
695 
696  return SCIP_OKAY;
697 }
698 
699 /** initialize the sorted event point arrays */
700 static
702  SCIP* scip, /**< SCIP data structure */
703  int nvars, /**< number of start time variables (activities) */
704  SCIP_VAR** vars, /**< array of start time variables */
705  int* durations, /**< array of durations per start time variable */
706  int* starttimes, /**< array to store sorted start events */
707  int* endtimes, /**< array to store sorted end events */
708  int* startindices, /**< permutation with rspect to the start times */
709  int* endindices, /**< permutation with rspect to the end times */
710  SCIP_Bool local /**< shall local bounds be used */
711  )
712 {
713  SCIP_VAR* var;
714  int j;
715 
716  assert(vars != NULL || nvars == 0);
717 
718  /* assign variables, start and endpoints to arrays */
719  for ( j = 0; j < nvars; ++j )
720  {
721  assert(vars != NULL);
722 
723  var = vars[j];
724  assert(var != NULL);
725 
726  if( local )
727  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
728  else
729  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
730 
731  startindices[j] = j;
732 
733  if( local )
734  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
735  else
736  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
737 
738  endindices[j] = j;
739  }
740 
741  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
742  SCIPsortIntInt(starttimes, startindices, j);
743  SCIPsortIntInt(endtimes, endindices, j);
744 }
745 
746 /** initialize the sorted event point arrays w.r.t. the given primal solutions */
747 static
749  SCIP* scip, /**< SCIP data structure */
750  SCIP_SOL* sol, /**< solution */
751  int nvars, /**< number of start time variables (activities) */
752  SCIP_VAR** vars, /**< array of start time variables */
753  int* durations, /**< array of durations per start time variable */
754  int* starttimes, /**< array to store sorted start events */
755  int* endtimes, /**< array to store sorted end events */
756  int* startindices, /**< permutation with rspect to the start times */
757  int* endindices /**< permutation with rspect to the end times */
758  )
759 {
760  SCIP_VAR* var;
761  int j;
762 
763  assert(vars != NULL || nvars == 0);
764 
765  /* assign variables, start and endpoints to arrays */
766  for ( j = 0; j < nvars; ++j )
767  {
768  assert(vars != NULL);
769 
770  var = vars[j];
771  assert(var != NULL);
772 
773  starttimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
774  startindices[j] = j;
775 
776  endtimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
777  endindices[j] = j;
778  }
779 
780  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
781  SCIPsortIntInt(starttimes, startindices, j);
782  SCIPsortIntInt(endtimes, endindices, j);
783 }
784 
785 /** initialize the sorted event point arrays
786  *
787  * @todo Check the separation process!
788  */
789 static
791  SCIP* scip, /**< SCIP data structure */
792  SCIP_CONSDATA* consdata, /**< constraint data */
793  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
794  int* starttimes, /**< array to store sorted start events */
795  int* endtimes, /**< array to store sorted end events */
796  int* startindices, /**< permutation with rspect to the start times */
797  int* endindices, /**< permutation with rspect to the end times */
798  int* nvars, /**< number of variables that are integral */
799  SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
800  )
801 {
802  SCIP_VAR* var;
803  int tmpnvars;
804  int j;
805 
806  tmpnvars = consdata->nvars;
807  *nvars = 0;
808 
809  /* assign variables, start and endpoints to arrays */
810  for ( j = 0; j < tmpnvars; ++j )
811  {
812  var = consdata->vars[j];
813  assert(var != NULL);
814  assert(consdata->durations[j] > 0);
815  assert(consdata->demands[j] > 0);
816 
817  if( lower )
818  {
819  /* only consider jobs that are at their lower or upper bound */
820  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
821  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
822  continue;
823 
824  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
825  startindices[*nvars] = j;
826 
827  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
828  endindices[*nvars] = j;
829 
830  SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
831  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
832  consdata->durations[j],
833  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
834  consdata->demands[startindices[*nvars]]);
835 
836  (*nvars)++;
837  }
838  else
839  {
840  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
841  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
842  continue;
843 
844  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
845  startindices[*nvars] = j;
846 
847  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
848  endindices[*nvars] = j;
849 
850  SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
851  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
852  consdata->durations[j],
853  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
854  consdata->demands[startindices[*nvars]]);
855 
856  (*nvars)++;
857  }
858  }
859 
860  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
861  SCIPsortIntInt(starttimes, startindices, *nvars);
862  SCIPsortIntInt(endtimes, endindices, *nvars);
863 
864 #ifdef SCIP_DEBUG
865  SCIPdebugMsg(scip, "sorted output %d\n", *nvars);
866 
867  for ( j = 0; j < *nvars; ++j )
868  {
869  SCIPdebugMsg(scip, "%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
870  startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
871  consdata->demands[startindices[j]]);
872  }
873 
874  for ( j = 0; j < *nvars; ++j )
875  {
876  SCIPdebugMsg(scip, "%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
877  consdata->demands[endindices[j]]);
878  }
879 #endif
880 }
881 
882 #ifdef SCIP_STATISTIC
883 /** this method checks for relevant intervals for energetic reasoning */
884 static
885 SCIP_RETCODE computeRelevantEnergyIntervals(
886  SCIP* scip, /**< SCIP data structure */
887  int nvars, /**< number of start time variables (activities) */
888  SCIP_VAR** vars, /**< array of start time variables */
889  int* durations, /**< array of durations */
890  int* demands, /**< array of demands */
891  int capacity, /**< cumulative capacity */
892  int hmin, /**< left bound of time axis to be considered (including hmin) */
893  int hmax, /**< right bound of time axis to be considered (not including hmax) */
894  int** timepoints, /**< array to store relevant points in time */
895  SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
896  int* ntimepoints, /**< pointer to store the number of timepoints */
897  int* maxdemand, /**< pointer to store maximum over all demands */
898  SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
899  )
900 {
901  int* starttimes; /* stores when each job is starting */
902  int* endtimes; /* stores when each job ends */
903  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
904  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
905 
906  SCIP_Real totaldemand;
907  int curtime; /* point in time which we are just checking */
908  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
909 
910  int j;
911 
912  assert( scip != NULL );
913  assert(durations != NULL);
914  assert(demands != NULL);
915  assert(capacity >= 0);
916 
917  /* if no activities are associated with this cumulative then this constraint is redundant */
918  if( nvars == 0 )
919  return SCIP_OKAY;
920 
921  assert(vars != NULL);
922 
923  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
924  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
925  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
926  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
927 
928  /* create event point arrays */
929  createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
930 
931  endindex = 0;
932  totaldemand = 0.0;
933 
934  *ntimepoints = 0;
935  (*timepoints)[0] = starttimes[0];
936  (*cumulativedemands)[0] = 0;
937  *maxdemand = 0;
938 
939  /* check each startpoint of a job whether the capacity is kept or not */
940  for( j = 0; j < nvars; ++j )
941  {
942  int lct;
943  int idx;
944 
945  curtime = starttimes[j];
946 
947  if( curtime >= hmax )
948  break;
949 
950  /* free all capacity usages of jobs the are no longer running */
951  while( endindex < nvars && endtimes[endindex] <= curtime )
952  {
953  int est;
954 
955  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
956  {
957  (*ntimepoints)++;
958  (*timepoints)[*ntimepoints] = endtimes[endindex];
959  (*cumulativedemands)[*ntimepoints] = 0;
960  }
961 
962  idx = endindices[endindex];
963  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
964  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
965  endindex++;
966 
967  (*cumulativedemands)[*ntimepoints] = totaldemand;
968  }
969 
970  idx = startindices[j];
971  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
972  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
973 
974  if( (*timepoints)[*ntimepoints] < curtime )
975  {
976  (*ntimepoints)++;
977  (*timepoints)[*ntimepoints] = curtime;
978  (*cumulativedemands)[*ntimepoints] = 0;
979  }
980 
981  (*cumulativedemands)[*ntimepoints] = totaldemand;
982 
983  /* add the relative capacity requirements for all job which start at the curtime */
984  while( j+1 < nvars && starttimes[j+1] == curtime )
985  {
986  ++j;
987  idx = startindices[j];
988  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
989  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
990 
991  (*cumulativedemands)[*ntimepoints] = totaldemand;
992  }
993  } /*lint --e{850}*/
994 
995  /* free all capacity usages of jobs that are no longer running */
996  while( endindex < nvars/* && endtimes[endindex] < hmax*/)
997  {
998  int est;
999  int idx;
1000 
1001  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
1002  {
1003  (*ntimepoints)++;
1004  (*timepoints)[*ntimepoints] = endtimes[endindex];
1005  (*cumulativedemands)[*ntimepoints] = 0;
1006  }
1007 
1008  idx = endindices[endindex];
1009  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
1010  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
1011  (*cumulativedemands)[*ntimepoints] = totaldemand;
1012 
1013  ++endindex;
1014  }
1015 
1016  (*ntimepoints)++;
1017  /* compute minimum free capacity */
1018  (*minfreecapacity) = INT_MAX;
1019  for( j = 0; j < *ntimepoints; ++j )
1020  {
1021  if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
1022  *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
1023  }
1024 
1025  /* free buffer arrays */
1026  SCIPfreeBufferArray(scip, &endindices);
1027  SCIPfreeBufferArray(scip, &startindices);
1028  SCIPfreeBufferArray(scip, &endtimes);
1029  SCIPfreeBufferArray(scip, &starttimes);
1030 
1031  return SCIP_OKAY;
1032 }
1033 
1034 /** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1035 static
1036 SCIP_RETCODE evaluateCumulativeness(
1037  SCIP* scip, /**< pointer to scip */
1038  SCIP_CONS* cons /**< cumulative constraint */
1039  )
1040 {
1041  SCIP_CONSDATA* consdata;
1042  int nvars;
1043  int v;
1044  int capacity;
1045 
1046  /* output values: */
1047  SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
1048  SCIP_Real cumfactor1;
1049  SCIP_Real resstrength1; /* overall strength */
1050  SCIP_Real resstrength2; /* timepoint wise maximum */
1051 
1052  /* helpful variables: */
1053  SCIP_Real globalpeak;
1054  SCIP_Real globalmaxdemand;
1055 
1056  /* get constraint data structure */
1057  consdata = SCIPconsGetData(cons);
1058  assert(consdata != NULL);
1059 
1060  nvars = consdata->nvars;
1061  capacity = consdata->capacity;
1062  globalpeak = 0.0;
1063  globalmaxdemand = 0.0;
1064 
1065  disjfactor2 = 0.0;
1066  cumfactor1 = 0.0;
1067  resstrength2 = 0.0;
1068 
1069  /* check each starting time (==each job, but inefficient) */
1070  for( v = 0; v < nvars; ++v )
1071  {
1072  SCIP_Real peak;
1073  SCIP_Real maxdemand;
1074  SCIP_Real deltademand;
1075  int ndemands;
1076  int nlarge;
1077 
1078  int timepoint;
1079  int j;
1080  timepoint = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
1081  peak = consdata->demands[v];
1082  ndemands = 1;
1083  maxdemand = 0;
1084  nlarge = 0;
1085 
1086  if( consdata->demands[v] > capacity / 3 )
1087  nlarge++;
1088 
1089  for( j = 0; j < nvars; ++j )
1090  {
1091  int lb;
1092 
1093  if( j == v )
1094  continue;
1095 
1096  maxdemand = 0.0;
1097  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
1098 
1099  if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
1100  {
1101  peak += consdata->demands[j];
1102  ndemands++;
1103 
1104  if( consdata->demands[j] > consdata->capacity / 3 )
1105  nlarge++;
1106  }
1107  }
1108 
1109  deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
1110  globalpeak = MAX(globalpeak, peak);
1111  globalmaxdemand = MAX(globalmaxdemand, maxdemand);
1112 
1113  if( peak > capacity )
1114  {
1115  disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
1116  cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
1117  resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
1118  }
1119  }
1120 
1121  resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
1122 
1123  consdata->maxpeak = SCIPconvertRealToInt(scip, globalpeak);
1124  consdata->disjfactor2 = disjfactor2;
1125  consdata->cumfactor1 = cumfactor1;
1126  consdata->resstrength2 = resstrength2;
1127  consdata->resstrength1 = resstrength1;
1128 
1129  /* get estimated res strength */
1130  {
1131  int* timepoints;
1132  SCIP_Real* estimateddemands;
1133  int ntimepoints;
1134  int maxdemand;
1135  SCIP_Real minfreecapacity;
1136 
1137  SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
1138  SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
1139 
1140  ntimepoints = 0;
1141  minfreecapacity = INT_MAX;
1142 
1143  SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
1144  consdata->durations, consdata->demands,
1145  capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1146  &ntimepoints, &maxdemand, &minfreecapacity) );
1147 
1148  /* free buffer arrays */
1149  SCIPfreeBufferArray(scip, &estimateddemands);
1150  SCIPfreeBufferArray(scip, &timepoints);
1151 
1152  consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
1153  }
1154 
1155  SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
1156  SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
1157  consdata->estimatedstrength);
1158 
1159  return SCIP_OKAY;
1160 }
1161 #endif
1162 
1163 /** gets the active variables together with the constant */
1164 static
1166  SCIP* scip, /**< SCIP data structure */
1167  SCIP_VAR** var, /**< pointer to store the active variable */
1168  int* scalar, /**< pointer to store the scalar */
1169  int* constant /**< pointer to store the constant */
1170  )
1171 {
1172  if( !SCIPvarIsActive(*var) )
1173  {
1174  SCIP_Real realscalar;
1175  SCIP_Real realconstant;
1176 
1177  realscalar = 1.0;
1178  realconstant = 0.0;
1179 
1181 
1182  /* transform variable to active variable */
1183  SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
1184  assert(!SCIPisZero(scip, realscalar));
1185  assert(SCIPvarIsActive(*var));
1186 
1187  if( realconstant < 0.0 )
1188  (*constant) = -SCIPconvertRealToInt(scip, -realconstant);
1189  else
1190  (*constant) = SCIPconvertRealToInt(scip, realconstant);
1191 
1192  if( realscalar < 0.0 )
1193  (*scalar) = -SCIPconvertRealToInt(scip, -realscalar);
1194  else
1195  (*scalar) = SCIPconvertRealToInt(scip, realscalar);
1196  }
1197  else
1198  {
1199  (*scalar) = 1;
1200  (*constant) = 0;
1201  }
1202 
1203  assert(*scalar != 0);
1204 
1205  return SCIP_OKAY;
1206 }
1207 
1208 /** computes the total energy of all jobs */
1209 static
1211  int* durations, /**< array of job durations */
1212  int* demands, /**< array of job demands */
1213  int njobs /**< number of jobs */
1214  )
1215 {
1216  SCIP_Longint energy;
1217  int j;
1218 
1219  energy = 0;
1220 
1221  for( j = 0; j < njobs; ++j )
1222  energy += (SCIP_Longint) durations[j] * demands[j];
1223 
1224  return energy;
1225 }
1226 
1227 /**@} */
1228 
1229 /**@name Default method to solve a cumulative condition
1230  *
1231  * @{
1232  */
1233 
1234 /** setup and solve subscip to solve single cumulative condition */
1235 static
1237  SCIP* subscip, /**< subscip data structure */
1238  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
1239  int* durations, /**< array of durations */
1240  int* demands, /**< array of demands */
1241  int njobs, /**< number of jobs (activities) */
1242  int capacity, /**< cumulative capacity */
1243  int hmin, /**< left bound of time axis to be considered (including hmin) */
1244  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1245  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes (-1: no limit) */
1246  SCIP_Real timelimit, /**< time limit for solving in seconds */
1247  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
1248  SCIP_Real* ests, /**< array of earliest start times for each job */
1249  SCIP_Real* lsts, /**< array of latest start times for each job */
1250  SCIP_Bool* infeasible, /**< pointer to store if the subproblem was infeasible */
1251  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
1252  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
1253  SCIP_Bool* error /**< pointer to store if an error occurred */
1254  )
1255 {
1256  SCIP_VAR** subvars;
1257  SCIP_CONS* cons;
1258 
1259  char name[SCIP_MAXSTRLEN];
1260  int v;
1261  SCIP_RETCODE retcode;
1262 
1263  assert(subscip != NULL);
1264 
1265  /* copy all plugins */
1267 
1268  /* create the subproblem */
1269  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1270 
1271  SCIP_CALL( SCIPallocBlockMemoryArray(subscip, &subvars, njobs) );
1272 
1273  /* create for each job a start time variable */
1274  for( v = 0; v < njobs; ++v )
1275  {
1276  SCIP_Real objval;
1277 
1278  /* construct variable name */
1279  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
1280 
1281  if( objvals == NULL )
1282  objval = 0.0;
1283  else
1284  objval = objvals[v];
1285 
1286  SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
1287  SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
1288  }
1289 
1290  /* create cumulative constraint */
1291  SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
1292  njobs, subvars, durations, demands, capacity) );
1293 
1294  /* set effective horizon */
1295  SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
1296  SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
1297 
1298  /* add cumulative constraint */
1299  SCIP_CALL( SCIPaddCons(subscip, cons) );
1300  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1301 
1302  /* set CP solver settings
1303  *
1304  * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
1305  * time limit.
1306  */
1308 
1309  /* do not abort subproblem on CTRL-C */
1310  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1311 
1312  /* disable output to console */
1313  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1314 
1315  /* set limits for the subproblem */
1316  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1317  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1318  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1319 
1320  /* forbid recursive call of heuristics and separators solving subMIPs */
1321  SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
1322 
1323  /* solve single cumulative constraint by branch and bound */
1324  retcode = SCIPsolve(subscip);
1325 
1326  if( retcode != SCIP_OKAY )
1327  (*error) = TRUE;
1328  else
1329  {
1330  SCIPdebugMsg(subscip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1331 
1332  /* evaluated solution status */
1333  switch( SCIPgetStatus(subscip) )
1334  {
1335  case SCIP_STATUS_INFORUNBD:
1337  (*infeasible) = TRUE;
1338  (*solved) = TRUE;
1339  break;
1340  case SCIP_STATUS_UNBOUNDED:
1341  (*unbounded) = TRUE;
1342  (*solved) = TRUE;
1343  break;
1344  case SCIP_STATUS_OPTIMAL:
1345  {
1346  SCIP_SOL* sol;
1347  SCIP_Real solval;
1348 
1349  sol = SCIPgetBestSol(subscip);
1350  assert(sol != NULL);
1351 
1352  for( v = 0; v < njobs; ++v )
1353  {
1354  solval = SCIPgetSolVal(subscip, sol, subvars[v]);
1355 
1356  ests[v] = solval;
1357  lsts[v] = solval;
1358  }
1359  (*solved) = TRUE;
1360  break;
1361  }
1362  case SCIP_STATUS_NODELIMIT:
1364  case SCIP_STATUS_TIMELIMIT:
1365  case SCIP_STATUS_MEMLIMIT:
1367  case SCIP_STATUS_TERMINATE:
1368  /* transfer the global bound changes */
1369  for( v = 0; v < njobs; ++v )
1370  {
1371  ests[v] = SCIPvarGetLbGlobal(subvars[v]);
1372  lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
1373  }
1374  (*solved) = FALSE;
1375  break;
1376 
1377  case SCIP_STATUS_UNKNOWN:
1379  case SCIP_STATUS_GAPLIMIT:
1380  case SCIP_STATUS_SOLLIMIT:
1383  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1384  return SCIP_INVALIDDATA;
1385  }
1386  }
1387 
1388  /* release all variables */
1389  for( v = 0; v < njobs; ++v )
1390  {
1391  SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1392  }
1393 
1394  SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
1395 
1396  return SCIP_OKAY;
1397 }
1398 
1399 /** solve single cumulative condition using SCIP and a single cumulative constraint */
1400 static
1401 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1403  SCIP* subscip;
1404 
1405  SCIP_RETCODE retcode;
1406 
1407  assert(njobs > 0);
1408 
1409  (*solved) = FALSE;
1410  (*infeasible) = FALSE;
1411  (*unbounded) = FALSE;
1412  (*error) = FALSE;
1413 
1414  SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1415 
1416  /* initialize the sub-problem */
1417  SCIP_CALL( SCIPcreate(&subscip) );
1418 
1419  /* create and solve the subproblem. catch possible errors */
1420  retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
1421  njobs, capacity, hmin, hmax,
1422  maxnodes, timelimit, memorylimit,
1423  ests, lsts,
1424  infeasible, unbounded, solved, error);
1425 
1426  /* free the subscip in any case */
1427  SCIP_CALL( SCIPfree(&subscip) );
1428 
1429  SCIP_CALL( retcode );
1430 
1431  return SCIP_OKAY;
1432 }
1433 
1434 #if 0
1435 /** solve single cumulative condition using SCIP and the time indexed formulation */
1436 static
1437 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1438 {
1439  SCIP* subscip;
1440  SCIP_VAR*** binvars;
1441  SCIP_RETCODE retcode;
1442  char name[SCIP_MAXSTRLEN];
1443  int minest;
1444  int maxlct;
1445  int t;
1446  int v;
1447 
1448  assert(njobs > 0);
1449 
1450  (*solved) = FALSE;
1451  (*infeasible) = FALSE;
1452  (*unbounded) = FALSE;
1453  (*error) = FALSE;
1454 
1455  SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
1456 
1457  /* initialize the sub-problem */
1458  SCIP_CALL( SCIPcreate(&subscip) );
1459 
1460  /* copy all plugins */
1462 
1463  /* create the subproblem */
1464  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1465 
1466  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
1467 
1468  minest = INT_MAX;
1469  maxlct = INT_MIN;
1470 
1471  /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1472  * partitioning constrain which forces that job starts
1473  */
1474  for( v = 0; v < njobs; ++v )
1475  {
1476  SCIP_CONS* cons;
1477  SCIP_Real objval;
1478  int timeinterval;
1479  int est;
1480  int lst;
1481 
1482  if( objvals == NULL )
1483  objval = 0.0;
1484  else
1485  objval = objvals[v];
1486 
1487  est = ests[v];
1488  lst = lsts[v];
1489 
1490  /* compute number of possible start points */
1491  timeinterval = lst - est + 1;
1492  assert(timeinterval > 0);
1493 
1494  /* compute the smallest earliest start time and largest latest completion time */
1495  minest = MIN(minest, est);
1496  maxlct = MAX(maxlct, lst + durations[v]);
1497 
1498  /* construct constraint name */
1499  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1500 
1501  SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1502 
1503  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
1504 
1505  for( t = 0; t < timeinterval; ++t )
1506  {
1507  SCIP_VAR* binvar;
1508 
1509  /* construct varibale name */
1510  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1511 
1512  SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1513  SCIP_CALL( SCIPaddVar(subscip, binvar) );
1514 
1515  /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1516  SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1517 
1518  binvars[v][t] = binvar;
1519  }
1520 
1521  /* add and release the set partitioning constraint */
1522  SCIP_CALL( SCIPaddCons(subscip, cons) );
1523  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1524  }
1525 
1526  /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1527  hmin = MAX(hmin, minest);
1528  hmax = MIN(hmax, maxlct);
1529  assert(hmin > INT_MIN);
1530  assert(hmax < INT_MAX);
1531  assert(hmin < hmax);
1532 
1533  /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1534  for( t = hmin; t < hmax; ++t )
1535  {
1536  SCIP_CONS* cons;
1537 
1538  /* construct constraint name */
1539  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1540 
1541  /* create an empty knapsack constraint */
1542  SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1543 
1544  /* add all jobs which potentially can be processed at that time point */
1545  for( v = 0; v < njobs; ++v )
1546  {
1547  int duration;
1548  int demand;
1549  int start;
1550  int end;
1551  int est;
1552  int lst;
1553  int k;
1554 
1555  est = ests[v];
1556  lst = lsts[v] ;
1557 
1558  duration = durations[v];
1559  assert(duration > 0);
1560 
1561  /* check if the varibale is processed potentially at time point t */
1562  if( t < est || t >= lst + duration )
1563  continue;
1564 
1565  demand = demands[v];
1566  assert(demand >= 0);
1567 
1568  start = MAX(t - duration + 1, est);
1569  end = MIN(t, lst);
1570 
1571  assert(start <= end);
1572 
1573  for( k = start; k <= end; ++k )
1574  {
1575  assert(binvars[v][k] != NULL);
1576  SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1577  }
1578  }
1579 
1580  /* add and release the knapsack constraint */
1581  SCIP_CALL( SCIPaddCons(subscip, cons) );
1582  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1583  }
1584 
1585  /* do not abort subproblem on CTRL-C */
1586  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1587 
1588  /* disable output to console */
1589  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1590 
1591  /* set limits for the subproblem */
1592  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1593  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1594  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1595 
1596  /* solve single cumulative constraint by branch and bound */
1597  retcode = SCIPsolve(subscip);
1598 
1599  if( retcode != SCIP_OKAY )
1600  (*error) = TRUE;
1601  else
1602  {
1603  SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1604 
1605  /* evaluated solution status */
1606  switch( SCIPgetStatus(subscip) )
1607  {
1608  case SCIP_STATUS_INFORUNBD:
1610  (*infeasible) = TRUE;
1611  (*solved) = TRUE;
1612  break;
1613  case SCIP_STATUS_UNBOUNDED:
1614  (*unbounded) = TRUE;
1615  (*solved) = TRUE;
1616  break;
1617  case SCIP_STATUS_OPTIMAL:
1618  {
1619  SCIP_SOL* sol;
1620 
1621  sol = SCIPgetBestSol(subscip);
1622  assert(sol != NULL);
1623 
1624  for( v = 0; v < njobs; ++v )
1625  {
1626  int timeinterval;
1627  int est;
1628  int lst;
1629 
1630  est = ests[v];
1631  lst = lsts[v];
1632 
1633  /* compute number of possible start points */
1634  timeinterval = lst - est + 1;
1635 
1636  /* check which binary varibale is set to one */
1637  for( t = 0; t < timeinterval; ++t )
1638  {
1639  if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1640  {
1641  ests[v] = est + t;
1642  lsts[v] = est + t;
1643  break;
1644  }
1645  }
1646  }
1647 
1648  (*solved) = TRUE;
1649  break;
1650  }
1651  case SCIP_STATUS_NODELIMIT:
1653  case SCIP_STATUS_TIMELIMIT:
1654  case SCIP_STATUS_MEMLIMIT:
1656  /* transfer the global bound changes */
1657  for( v = 0; v < njobs; ++v )
1658  {
1659  int timeinterval;
1660  int est;
1661  int lst;
1662 
1663  est = ests[v];
1664  lst = lsts[v];
1665 
1666  /* compute number of possible start points */
1667  timeinterval = lst - est + 1;
1668 
1669  /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1670  for( t = 0; t < timeinterval; ++t )
1671  {
1672  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1673  {
1674  ests[v] = est + t;
1675  break;
1676  }
1677  }
1678 
1679  /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1680  for( t = timeinterval - 1; t >= 0; --t )
1681  {
1682  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1683  {
1684  lsts[v] = est + t;
1685  break;
1686  }
1687  }
1688  }
1689  (*solved) = FALSE;
1690  break;
1691 
1692  case SCIP_STATUS_UNKNOWN:
1694  case SCIP_STATUS_GAPLIMIT:
1695  case SCIP_STATUS_SOLLIMIT:
1697  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1698  return SCIP_INVALIDDATA;
1699  }
1700  }
1701 
1702  /* release all variables */
1703  for( v = 0; v < njobs; ++v )
1704  {
1705  int timeinterval;
1706  int est;
1707  int lst;
1708 
1709  est = ests[v];
1710  lst = lsts[v];
1711 
1712  /* compute number of possible start points */
1713  timeinterval = lst - est + 1;
1714 
1715  for( t = 0; t < timeinterval; ++t )
1716  {
1717  SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1718  }
1719  SCIPfreeBufferArray(subscip, &binvars[v]);
1720  }
1721 
1722  SCIPfreeBufferArray(subscip, &binvars);
1723 
1724  SCIP_CALL( SCIPfree(&subscip) );
1725 
1726  return SCIP_OKAY;
1727 }
1728 #endif
1729 
1730 /**@} */
1731 
1732 /**@name Constraint handler data
1733  *
1734  * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1735  * handler.
1736  *
1737  * @{
1738  */
1739 
1740 /** creates constaint handler data for cumulative constraint handler */
1741 static
1743  SCIP* scip, /**< SCIP data structure */
1744  SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1745  SCIP_EVENTHDLR* eventhdlr /**< event handler */
1746  )
1747 {
1748  /* create precedence constraint handler data */
1749  assert(scip != NULL);
1750  assert(conshdlrdata != NULL);
1751  assert(eventhdlr != NULL);
1752 
1753  SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
1754 
1755  /* set event handler for checking if bounds of start time variables are tighten */
1756  (*conshdlrdata)->eventhdlr = eventhdlr;
1757 
1758  /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1759  (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1760 
1761 #ifdef SCIP_STATISTIC
1762  (*conshdlrdata)->nlbtimetable = 0;
1763  (*conshdlrdata)->nubtimetable = 0;
1764  (*conshdlrdata)->ncutofftimetable = 0;
1765  (*conshdlrdata)->nlbedgefinder = 0;
1766  (*conshdlrdata)->nubedgefinder = 0;
1767  (*conshdlrdata)->ncutoffedgefinder = 0;
1768  (*conshdlrdata)->ncutoffoverload = 0;
1769  (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1770 
1771  (*conshdlrdata)->nirrelevantjobs = 0;
1772  (*conshdlrdata)->nalwaysruns = 0;
1773  (*conshdlrdata)->nremovedlocks = 0;
1774  (*conshdlrdata)->ndualfixs = 0;
1775  (*conshdlrdata)->ndecomps = 0;
1776  (*conshdlrdata)->ndualbranchs = 0;
1777  (*conshdlrdata)->nallconsdualfixs = 0;
1778  (*conshdlrdata)->naddedvarbounds = 0;
1779  (*conshdlrdata)->naddeddisjunctives = 0;
1780 #endif
1781 
1782  return SCIP_OKAY;
1783 }
1784 
1785 /** frees constraint handler data for logic or constraint handler */
1786 static
1787 void conshdlrdataFree(
1788  SCIP* scip, /**< SCIP data structure */
1789  SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1790  )
1791 {
1792  assert(conshdlrdata != NULL);
1793  assert(*conshdlrdata != NULL);
1794 
1795  SCIPfreeBlockMemory(scip, conshdlrdata);
1796 }
1797 
1798 /**@} */
1799 
1800 
1801 /**@name Constraint data methods
1802  *
1803  * @{
1804  */
1805 
1806 /** catches bound change events for all variables in transformed cumulative constraint */
1807 static
1809  SCIP* scip, /**< SCIP data structure */
1810  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1811  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1812  )
1813 {
1814  int v;
1815 
1816  assert(scip != NULL);
1817  assert(consdata != NULL);
1818  assert(eventhdlr != NULL);
1819 
1820  /* catch event for every single variable */
1821  for( v = 0; v < consdata->nvars; ++v )
1822  {
1823  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1824  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1825  }
1826 
1827  return SCIP_OKAY;
1828 }
1829 
1830 /** drops events for variable at given position */
1831 static
1833  SCIP* scip, /**< SCIP data structure */
1834  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1835  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1836  int pos /**< array position of variable to catch bound change events for */
1837  )
1838 {
1839  assert(scip != NULL);
1840  assert(consdata != NULL);
1841  assert(eventhdlr != NULL);
1842  assert(0 <= pos && pos < consdata->nvars);
1843  assert(consdata->vars[pos] != NULL);
1844 
1845  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1846  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1847 
1848  return SCIP_OKAY;
1849 }
1850 
1851 /** drops bound change events for all variables in transformed linear constraint */
1852 static
1854  SCIP* scip, /**< SCIP data structure */
1855  SCIP_CONSDATA* consdata, /**< linear constraint data */
1856  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1857  )
1858 {
1859  int v;
1860 
1861  assert(scip != NULL);
1862  assert(consdata != NULL);
1863 
1864  /* drop event of every single variable */
1865  for( v = 0; v < consdata->nvars; ++v )
1866  {
1867  SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1868  }
1869 
1870  return SCIP_OKAY;
1871 }
1872 
1873 /** initialize variable lock data structure */
1874 static
1875 void initializeLocks(
1876  SCIP_CONSDATA* consdata, /**< constraint data */
1877  SCIP_Bool locked /**< should the variable be locked? */
1878  )
1879 {
1880  int nvars;
1881  int v;
1882 
1883  nvars = consdata->nvars;
1884 
1885  /* initialize locking arrays */
1886  for( v = 0; v < nvars; ++v )
1887  {
1888  consdata->downlocks[v] = locked;
1889  consdata->uplocks[v] = locked;
1890  }
1891 }
1892 
1893 /** creates constraint data of cumulative constraint */
1894 static
1896  SCIP* scip, /**< SCIP data structure */
1897  SCIP_CONSDATA** consdata, /**< pointer to consdata */
1898  SCIP_VAR** vars, /**< array of integer variables */
1899  SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1900  int* durations, /**< array containing corresponding durations */
1901  int* demands, /**< array containing corresponding demands */
1902  int nvars, /**< number of variables */
1903  int capacity, /**< available cumulative capacity */
1904  int hmin, /**< left bound of time axis to be considered (including hmin) */
1905  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1906  SCIP_Bool check /**< is the corresponding constraint a check constraint */
1907  )
1908 {
1909  int v;
1910 
1911  assert(scip != NULL);
1912  assert(consdata != NULL);
1913  assert(vars != NULL || nvars > 0);
1914  assert(demands != NULL);
1915  assert(durations != NULL);
1916  assert(capacity >= 0);
1917  assert(hmin >= 0);
1918  assert(hmin < hmax);
1919 
1920  /* create constraint data */
1921  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1922 
1923  (*consdata)->hmin = hmin;
1924  (*consdata)->hmax = hmax;
1925 
1926  (*consdata)->capacity = capacity;
1927  (*consdata)->demandrows = NULL;
1928  (*consdata)->demandrowssize = 0;
1929  (*consdata)->ndemandrows = 0;
1930  (*consdata)->scoverrows = NULL;
1931  (*consdata)->nscoverrows = 0;
1932  (*consdata)->scoverrowssize = 0;
1933  (*consdata)->bcoverrows = NULL;
1934  (*consdata)->nbcoverrows = 0;
1935  (*consdata)->bcoverrowssize = 0;
1936  (*consdata)->nvars = nvars;
1937  (*consdata)->varssize = nvars;
1938  (*consdata)->signature = 0;
1939  (*consdata)->validsignature = FALSE;
1940  (*consdata)->normalized = FALSE;
1941  (*consdata)->covercuts = FALSE;
1942  (*consdata)->propagated = FALSE;
1943  (*consdata)->varbounds = FALSE;
1944  (*consdata)->triedsolving = FALSE;
1945 
1946  if( nvars > 0 )
1947  {
1948  assert(vars != NULL); /* for flexelint */
1949 
1950  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1951  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1952  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1953  (*consdata)->linkingconss = NULL;
1954 
1955  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1956  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1957 
1958  /* initialize variable lock data structure; the locks are only used if the contraint is a check constraint */
1959  initializeLocks(*consdata, check);
1960 
1961  if( linkingconss != NULL )
1962  {
1963  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
1964  }
1965 
1966  /* transform variables, if they are not yet transformed */
1967  if( SCIPisTransformed(scip) )
1968  {
1969  SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
1970 
1971  /* get transformed variables and do NOT captures these */
1972  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1973 
1974  /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
1975  * been multi-aggregated
1976  */
1977  for( v = 0; v < nvars; ++v )
1978  {
1979  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
1980  }
1981 
1982  if( linkingconss != NULL )
1983  {
1984  /* get transformed constraints and captures these */
1985  SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
1986 
1987  for( v = 0; v < nvars; ++v )
1988  assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
1989  }
1990  }
1991  }
1992  else
1993  {
1994  (*consdata)->vars = NULL;
1995  (*consdata)->downlocks = NULL;
1996  (*consdata)->uplocks = NULL;
1997  (*consdata)->demands = NULL;
1998  (*consdata)->durations = NULL;
1999  (*consdata)->linkingconss = NULL;
2000  }
2001 
2002  /* initialize values for running propagation algorithms efficiently */
2003  (*consdata)->resstrength1 = -1.0;
2004  (*consdata)->resstrength2 = -1.0;
2005  (*consdata)->cumfactor1 = -1.0;
2006  (*consdata)->disjfactor1 = -1.0;
2007  (*consdata)->disjfactor2 = -1.0;
2008  (*consdata)->estimatedstrength = -1.0;
2009 
2010  SCIPstatistic( (*consdata)->maxpeak = -1 );
2011 
2012  return SCIP_OKAY;
2013 }
2014 
2015 /** releases LP rows of constraint data and frees rows array */
2016 static
2018  SCIP* scip, /**< SCIP data structure */
2019  SCIP_CONSDATA** consdata /**< constraint data */
2020  )
2021 {
2022  int r;
2023 
2024  assert(consdata != NULL);
2025  assert(*consdata != NULL);
2026 
2027  for( r = 0; r < (*consdata)->ndemandrows; ++r )
2028  {
2029  assert((*consdata)->demandrows[r] != NULL);
2030  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
2031  }
2032 
2033  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
2034 
2035  (*consdata)->ndemandrows = 0;
2036  (*consdata)->demandrowssize = 0;
2037 
2038  /* free rows of cover cuts */
2039  for( r = 0; r < (*consdata)->nscoverrows; ++r )
2040  {
2041  assert((*consdata)->scoverrows[r] != NULL);
2042  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
2043  }
2044 
2045  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
2046 
2047  (*consdata)->nscoverrows = 0;
2048  (*consdata)->scoverrowssize = 0;
2049 
2050  for( r = 0; r < (*consdata)->nbcoverrows; ++r )
2051  {
2052  assert((*consdata)->bcoverrows[r] != NULL);
2053  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2054  }
2055 
2056  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2057 
2058  (*consdata)->nbcoverrows = 0;
2059  (*consdata)->bcoverrowssize = 0;
2060 
2061  (*consdata)->covercuts = FALSE;
2062 
2063  return SCIP_OKAY;
2064 }
2065 
2066 /** frees a cumulative constraint data */
2067 static
2069  SCIP* scip, /**< SCIP data structure */
2070  SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2071  )
2072 {
2073  int varssize;
2074  int nvars;
2075 
2076  assert(consdata != NULL);
2077  assert(*consdata != NULL);
2078 
2079  nvars = (*consdata)->nvars;
2080  varssize = (*consdata)->varssize;
2081 
2082  if( varssize > 0 )
2083  {
2084  int v;
2085 
2086  /* release and free the rows */
2087  SCIP_CALL( consdataFreeRows(scip, consdata) );
2088 
2089  /* release the linking constraints if they were generated */
2090  if( (*consdata)->linkingconss != NULL )
2091  {
2092  for( v = nvars-1; v >= 0; --v )
2093  {
2094  assert((*consdata)->linkingconss[v] != NULL );
2095  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2096  }
2097 
2098  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2099  }
2100 
2101  /* free arrays */
2102  SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2103  SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2104  SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2105  SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2106  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2107  }
2108 
2109  /* free memory */
2110  SCIPfreeBlockMemory(scip, consdata);
2111 
2112  return SCIP_OKAY;
2113 }
2114 
2115 /** prints cumulative constraint to file stream */
2116 static
2117 void consdataPrint(
2118  SCIP* scip, /**< SCIP data structure */
2119  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2120  FILE* file /**< output file (or NULL for standard output) */
2121  )
2122 {
2123  int v;
2124 
2125  assert(consdata != NULL);
2126 
2127  /* print coefficients */
2128  SCIPinfoMessage( scip, file, "cumulative(");
2129 
2130  for( v = 0; v < consdata->nvars; ++v )
2131  {
2132  assert(consdata->vars[v] != NULL);
2133  if( v > 0 )
2134  SCIPinfoMessage(scip, file, ", ");
2135  SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2136  SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2137  consdata->durations[v], consdata->demands[v]);
2138  }
2139  SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2140 }
2141 
2142 /** deletes coefficient at given position from constraint data */
2143 static
2145  SCIP* scip, /**< SCIP data structure */
2146  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2147  SCIP_CONS* cons, /**< knapsack constraint */
2148  int pos /**< position of coefficient to delete */
2149  )
2150 {
2151  SCIP_CONSHDLR* conshdlr;
2152  SCIP_CONSHDLRDATA* conshdlrdata;
2153 
2154  assert(scip != NULL);
2155  assert(consdata != NULL);
2156  assert(cons != NULL);
2157  assert(SCIPconsIsTransformed(cons));
2158  assert(!SCIPinProbing(scip));
2159 
2160  SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2161  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2162 
2163  /* remove the rounding locks for the deleted variable */
2164  SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2165 
2166  consdata->downlocks[pos] = FALSE;
2167  consdata->uplocks[pos] = FALSE;
2168 
2169  if( consdata->linkingconss != NULL )
2170  {
2171  SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2172  }
2173 
2174  /* get event handler */
2175  conshdlr = SCIPconsGetHdlr(cons);
2176  assert(conshdlr != NULL);
2177  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2178  assert(conshdlrdata != NULL);
2179  assert(conshdlrdata->eventhdlr != NULL);
2180 
2181  /* drop events */
2182  SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2183 
2184  SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2185  SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2186 
2187  /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2188  * position
2189  */
2190  if( pos != consdata->nvars - 1 )
2191  {
2192  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2193  consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2194  consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2195  consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2196  consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2197 
2198  if( consdata->linkingconss != NULL )
2199  {
2200  consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2201  }
2202  }
2203 
2204  consdata->nvars--;
2205  consdata->validsignature = FALSE;
2206  consdata->normalized = FALSE;
2207 
2208  return SCIP_OKAY;
2209 }
2210 
2211 /** collect linking constraints for each integer variable */
2212 static
2214  SCIP* scip, /**< SCIP data structure */
2215  SCIP_CONSDATA* consdata /**< pointer to consdata */
2216  )
2217 {
2218  int nvars;
2219  int v;
2220 
2221  assert(scip != NULL);
2222  assert(consdata != NULL);
2223 
2224  nvars = consdata->nvars;
2225  assert(nvars > 0);
2226  assert(consdata->linkingconss == NULL);
2227 
2228  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2229 
2230  for( v = 0; v < nvars; ++v )
2231  {
2232  SCIP_CONS* cons;
2233  SCIP_VAR* var;
2234 
2235  var = consdata->vars[v];
2236  assert(var != NULL);
2237 
2238  SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2239 
2240  /* create linking constraint if it does not exist yet */
2241  if( !SCIPexistsConsLinking(scip, var) )
2242  {
2243  char name[SCIP_MAXSTRLEN];
2244 
2245  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2246 
2247  /* creates and captures an linking constraint */
2248  SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2249  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2250  SCIP_CALL( SCIPaddCons(scip, cons) );
2251  consdata->linkingconss[v] = cons;
2252  }
2253  else
2254  {
2255  consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2256  SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2257  }
2258 
2259  assert(SCIPexistsConsLinking(scip, var));
2260  assert(consdata->linkingconss[v] != NULL);
2261  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2262  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2263  }
2264 
2265  return SCIP_OKAY;
2266 }
2267 
2268 /**@} */
2269 
2270 
2271 /**@name Check methods
2272  *
2273  * @{
2274  */
2275 
2276 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2277  * given solution is satisfied
2278  */
2279 static
2281  SCIP* scip, /**< SCIP data structure */
2282  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2283  int nvars, /**< number of variables (jobs) */
2284  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2285  int* durations, /**< array containing corresponding durations */
2286  int* demands, /**< array containing corresponding demands */
2287  int capacity, /**< available cumulative capacity */
2288  int hmin, /**< left bound of time axis to be considered (including hmin) */
2289  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2290  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2291  SCIP_CONS* cons, /**< constraint which is checked */
2292  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2293  )
2294 {
2295  int* startsolvalues; /* stores when each job is starting */
2296  int* endsolvalues; /* stores when each job ends */
2297  int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2298  int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2299 
2300  int freecapacity;
2301  int curtime; /* point in time which we are just checking */
2302  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2303  int j;
2304 
2305  SCIP_Real absviol;
2306  SCIP_Real relviol;
2307 
2308  assert(scip != NULL);
2309  assert(violated != NULL);
2310 
2311  (*violated) = FALSE;
2312 
2313  if( nvars == 0 )
2314  return SCIP_OKAY;
2315 
2316  assert(vars != NULL);
2317  assert(demands != NULL);
2318  assert(durations != NULL);
2319 
2320  /* compute time points where we have to check whether capacity constraint is infeasible or not */
2321  SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2322  SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2323  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2324  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2325 
2326  /* assign variables, start and endpoints to arrays */
2327  for ( j = 0; j < nvars; ++j )
2328  {
2329  int solvalue;
2330 
2331  /* the constraint of the cumulative constraint handler should be called after the integrality check */
2332  assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2333 
2334  solvalue = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2335 
2336  /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2337  * jobs which start before hmin to hmin
2338  */
2339  startsolvalues[j] = MAX(solvalue, hmin);
2340  startindices[j] = j;
2341 
2342  endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2343  endindices[j] = j;
2344  }
2345 
2346  /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2347  * corresponding indices in the same way)
2348  */
2349  SCIPsortIntInt(startsolvalues, startindices, nvars);
2350  SCIPsortIntInt(endsolvalues, endindices, nvars);
2351 
2352  endindex = 0;
2353  freecapacity = capacity;
2354  absviol = 0.0;
2355  relviol = 0.0;
2356 
2357  /* check each start point of a job whether the capacity is kept or not */
2358  for( j = 0; j < nvars; ++j )
2359  {
2360  /* only check intervals [hmin,hmax) */
2361  curtime = startsolvalues[j];
2362 
2363  if( curtime >= hmax )
2364  break;
2365 
2366  /* subtract all capacity needed up to this point */
2367  freecapacity -= demands[startindices[j]];
2368  while( j+1 < nvars && startsolvalues[j+1] == curtime )
2369  {
2370  j++;
2371  freecapacity -= demands[startindices[j]];
2372  }
2373 
2374  /* free all capacity usages of jobs that are no longer running */
2375  while( endindex < nvars && curtime >= endsolvalues[endindex] )
2376  {
2377  freecapacity += demands[endindices[endindex]];
2378  ++endindex;
2379  }
2380  assert(freecapacity <= capacity);
2381 
2382  /* update absolute and relative violation */
2383  if( absviol < (SCIP_Real) (-freecapacity) )
2384  {
2385  absviol = -freecapacity;
2386  relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
2387  }
2388 
2389  /* check freecapacity to be smaller than zero */
2390  if( freecapacity < 0 && curtime >= hmin )
2391  {
2392  SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2393  (*violated) = TRUE;
2394 
2395  if( printreason )
2396  {
2397  int i;
2398 
2399  /* first state the violated constraints */
2400  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2401 
2402  /* second state the reason */
2403  SCIPinfoMessage(scip, NULL,
2404  ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2405  curtime, capacity, capacity - freecapacity);
2406 
2407  for( i = 0; i <= j; ++i )
2408  {
2409  if( startsolvalues[i] + durations[startindices[i]] > curtime )
2410  {
2411  SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2412  SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2413  demands[startindices[i]]);
2414  }
2415  }
2416  }
2417  break;
2418  }
2419  } /*lint --e{850}*/
2420 
2421  /* update constraint violation in solution */
2422  if( sol != NULL )
2423  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
2424 
2425  /* free all buffer arrays */
2426  SCIPfreeBufferArray(scip, &endindices);
2427  SCIPfreeBufferArray(scip, &startindices);
2428  SCIPfreeBufferArray(scip, &endsolvalues);
2429  SCIPfreeBufferArray(scip, &startsolvalues);
2430 
2431  return SCIP_OKAY;
2432 }
2433 
2434 /** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2435  * least zero or not. If not (*violated) is set to TRUE
2436  */
2437 static
2439  SCIP* scip, /**< SCIP data structure */
2440  SCIP_CONS* cons, /**< constraint to be checked */
2441  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2442  SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2443  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2444  )
2445 {
2446  SCIP_CONSDATA* consdata;
2447 
2448  assert(scip != NULL);
2449  assert(cons != NULL);
2450  assert(violated != NULL);
2451 
2452  SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2453 
2454  consdata = SCIPconsGetData(cons);
2455  assert(consdata != NULL);
2456 
2457  /* check the cumulative condition */
2458  SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2459  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2460  violated, cons, printreason) );
2461 
2462  return SCIP_OKAY;
2463 }
2464 
2465 /**@} */
2466 
2467 /**@name Conflict analysis
2468  *
2469  * @{
2470  */
2471 
2472 /** resolves the propagation of the core time algorithm */
2473 static
2475  SCIP* scip, /**< SCIP data structure */
2476  int nvars, /**< number of start time variables (activities) */
2477  SCIP_VAR** vars, /**< array of start time variables */
2478  int* durations, /**< array of durations */
2479  int* demands, /**< array of demands */
2480  int capacity, /**< cumulative capacity */
2481  int hmin, /**< left bound of time axis to be considered (including hmin) */
2482  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2483  SCIP_VAR* infervar, /**< inference variable */
2484  int inferdemand, /**< demand of the inference variable */
2485  int inferpeak, /**< time point which causes the propagation */
2486  int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2487  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2488  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2489  int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2490  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2491  )
2492 {
2493  SCIP_VAR* var;
2494  SCIP_Bool* reported;
2495  int duration;
2496  int maxlst;
2497  int minect;
2498  int ect;
2499  int lst;
2500  int j;
2501 
2502  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
2503 
2504  SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2505  SCIPvarGetName(infervar), inferdemand, inferpeak);
2506  assert(nvars > 0);
2507 
2508  /* adjusted capacity */
2509  capacity -= inferdemand;
2510  maxlst = INT_MIN;
2511  minect = INT_MAX;
2512 
2513  SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2514  BMSclearMemoryArray(reported, nvars);
2515 
2516  /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2517  * inference peak and those where the current conflict bounds provide a core at the inference peak
2518  */
2519  for( j = 0; j < nvars && capacity >= 0; ++j )
2520  {
2521  var = vars[j];
2522  assert(var != NULL);
2523 
2524  /* skip inference variable */
2525  if( var == infervar )
2526  continue;
2527 
2528  duration = durations[j];
2529  assert(duration > 0);
2530 
2531  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2532  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2533  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2534  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2535  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2536 
2537  SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2539  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2540 
2541  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2542  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2543 
2544  /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2545  * that job without adding it the explanation
2546  */
2547  if( inferpeak < ect && lst <= inferpeak )
2548  {
2549  capacity -= demands[j];
2550  reported[j] = TRUE;
2551 
2552  maxlst = MAX(maxlst, lst);
2553  minect = MIN(minect, ect);
2554  assert(maxlst < minect);
2555 
2556  if( explanation != NULL )
2557  explanation[j] = TRUE;
2558 
2559  continue;
2560  }
2561 
2562  /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2563  * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2564  * not part of the conflict yet we get the global bounds back.
2565  */
2566  ect = SCIPconvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2567  lst = SCIPconvertRealToInt(scip, SCIPgetConflictVarUb(scip, var));
2568 
2569  /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2570  * of that job without and collect the job as part of the explanation
2571  *
2572  * @note we do not need to reported that job to SCIP since the required bounds are already reported
2573  */
2574  if( inferpeak < ect && lst <= inferpeak )
2575  {
2576  capacity -= demands[j];
2577  reported[j] = TRUE;
2578 
2579  maxlst = MAX(maxlst, lst);
2580  minect = MIN(minect, ect);
2581  assert(maxlst < minect);
2582 
2583  if( explanation != NULL )
2584  explanation[j] = TRUE;
2585  }
2586  }
2587 
2588  if( capacity >= 0 )
2589  {
2590  int* cands;
2591  int* canddemands;
2592  int ncands;
2593  int c;
2594 
2595  SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2596  SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2597  ncands = 0;
2598 
2599  /* collect all cores of the variables which lay in the considered time window except the inference variable */
2600  for( j = 0; j < nvars; ++j )
2601  {
2602  var = vars[j];
2603  assert(var != NULL);
2604 
2605  /* skip inference variable */
2606  if( var == infervar || reported[j] )
2607  continue;
2608 
2609  duration = durations[j];
2610  assert(duration > 0);
2611 
2612  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2613  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2614  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2615  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2616  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2617 
2618  /* collect local core information */
2619  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2620  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2621 
2622  SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2623  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2624  SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2625 
2626  /* check if the inference peak is part of the core */
2627  if( inferpeak < ect && lst <= inferpeak )
2628  {
2629  cands[ncands] = j;
2630  canddemands[ncands] = demands[j];
2631  ncands++;
2632 
2633  capacity -= demands[j];
2634  }
2635  }
2636 
2637  /* sort candidates indices w.r.t. their demands */
2638  SCIPsortDownIntInt(canddemands, cands, ncands);
2639 
2640  assert(capacity < 0);
2641  assert(ncands > 0);
2642 
2643  /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2644  while( capacity + canddemands[ncands-1] < 0 )
2645  {
2646  ncands--;
2647  capacity += canddemands[ncands];
2648  assert(ncands > 0);
2649  }
2650 
2651  /* compute the size (number of time steps) of the job cores */
2652  for( c = 0; c < ncands; ++c )
2653  {
2654  var = vars[cands[c]];
2655  assert(var != NULL);
2656 
2657  duration = durations[cands[c]];
2658 
2659  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2660  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2661 
2662  maxlst = MAX(maxlst, lst);
2663  minect = MIN(minect, ect);
2664  assert(maxlst < minect);
2665  }
2666 
2667  SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2668  assert(inferpeak >= maxlst);
2669  assert(inferpeak < minect);
2670 
2671  /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2672  if( relaxedpeak < inferpeak )
2673  {
2674  inferpeak = MAX(maxlst, relaxedpeak);
2675  }
2676  else if( relaxedpeak > inferpeak )
2677  {
2678  inferpeak = MIN(minect-1, relaxedpeak);
2679  }
2680  assert(inferpeak >= hmin);
2681  assert(inferpeak < hmax);
2682  assert(inferpeak >= maxlst);
2683  assert(inferpeak < minect);
2684 
2685  /* post all necessary bound changes */
2686  for( c = 0; c < ncands; ++c )
2687  {
2688  var = vars[cands[c]];
2689  assert(var != NULL);
2690 
2691  if( usebdwidening )
2692  {
2693  duration = durations[cands[c]];
2694 
2695  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2696  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2697  }
2698  else
2699  {
2700  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2701  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2702  }
2703 
2704  if( explanation != NULL )
2705  explanation[cands[c]] = TRUE;
2706  }
2707 
2708  SCIPfreeBufferArray(scip, &canddemands);
2709  SCIPfreeBufferArray(scip, &cands);
2710  }
2711 
2712  SCIPfreeBufferArray(scip, &reported);
2713 
2714  if( provedpeak != NULL )
2715  *provedpeak = inferpeak;
2716 
2717  return SCIP_OKAY;
2718 }
2719 
2720 #if 0
2721 /** repropagation of edge finding algorithm simplified version from Petr Vilim only a small subset is reported such that
2722  * energy in total and for bound change is enough
2723  */
2724 static
2725 SCIP_RETCODE resolvePropagationEdgeFinding(
2726  SCIP* scip, /**< SCIP data structure */
2727  int nvars, /**< number of start time variables (activities) */
2728  SCIP_VAR** vars, /**< array of start time variables */
2729  int* durations, /**< array of durations */
2730  int hmin, /**< left bound of time axis to be considered (including hmin) */
2731  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2732  SCIP_VAR* infervar, /**< variable whose bound change is to be explained */
2733  INFERINFO inferinfo, /**< inference info containing position of correct bdchgids */
2734  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2735  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2736  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2737  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2738  )
2739 {
2740  int est;
2741  int lct;
2742  int j;
2743 
2744  /* ???????????????????? do bound widening */
2745 
2746  assert(scip != NULL);
2747  assert(nvars > 0);
2748  assert(inferInfoGetProprule(inferinfo) == PROPRULE_2_EDGEFINDING);
2749 
2750  SCIPdebugMsg(scip, "repropagate edge-finding with short reasons for variable <%s>\n", SCIPvarGetName(infervar));
2751 
2752  if( boundtype == SCIP_BOUNDTYPE_LOWER )
2753  {
2754  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
2755  }
2756  else
2757  {
2758  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
2759  }
2760 
2761  est = inferInfoGetData1(inferinfo);
2762  lct = inferInfoGetData2(inferinfo);
2763  assert(est < lct);
2764 
2765  /* collect the energies of all variables in [est_omega, lct_omega] */
2766  for( j = 0; j < nvars; ++j )
2767  {
2768  SCIP_VAR* var;
2769  SCIP_Bool left;
2770  SCIP_Bool right;
2771  int duration;
2772  int lb;
2773  int ub;
2774 
2775  var = vars[j];
2776  assert(var != NULL);
2777 
2778  if( var == infervar )
2779  {
2780  if( explanation != NULL )
2781  explanation[j] = TRUE;
2782 
2783  continue;
2784  }
2785 
2786  lb = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
2787  ub = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2788 
2789  duration = durations[j];
2790  assert(duration > 0);
2791 
2792  /* in case the earliest start time is equal to hmin we have to also consider the jobs which run in that region
2793  * since we use adjusted jobs during the propagation
2794  */
2795  left = (est == hmin && lb + duration > hmin) || lb >= est;
2796 
2797  /* in case the latest completion time is equal to hmax we have to also consider the jobs which run in that region
2798  * since we use adjusted jobs during the propagation
2799  */
2800  right = (lct == hmax && ub < hmax) || ub + duration <= lct;
2801 
2802  /* store all jobs running in [est_omega; lct_omega] */
2803  if( left && right )
2804  {
2805  /* check if bound widening should be used */
2806  if( usebdwidening )
2807  {
2808  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(lct - duration)) );
2809  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(est)) );
2810  }
2811  else
2812  {
2813  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2814  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2815  }
2816 
2817  if( explanation != NULL )
2818  explanation[j] = TRUE;
2819  }
2820  }
2821 
2822  return SCIP_OKAY;
2823 }
2824 #endif
2825 
2826 /** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2827 static
2828 int computeOverlap(
2829  int begin, /**< begin of the times interval */
2830  int end, /**< end of time interval */
2831  int est, /**< earliest start time */
2832  int lst, /**< latest start time */
2833  int duration /**< duration of the job */
2834  )
2835 {
2836  int left;
2837  int right;
2838  int ect;
2839  int lct;
2840 
2841  ect = est + duration;
2842  lct = lst + duration;
2843 
2844  /* check if job runs completely within [begin,end) */
2845  if( lct <= end && est >= begin )
2846  return duration;
2847 
2848  assert(lst <= end && ect >= begin);
2849 
2850  left = ect - begin;
2851  assert(left > 0);
2852 
2853  right = end - lst;
2854  assert(right > 0);
2855 
2856  return MIN3(left, right, end - begin);
2857 }
2858 
2859 /** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2860  * reason
2861  *
2862  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2863  */
2864 static
2866  SCIP* scip, /**< SCIP data structure */
2867  int nvars, /**< number of start time variables (activities) */
2868  SCIP_VAR** vars, /**< array of start time variables */
2869  int* durations, /**< array of durations */
2870  int* demands, /**< array of demands */
2871  int capacity, /**< capacity of the cumulative condition */
2872  int begin, /**< begin of the time window */
2873  int end, /**< end of the time window */
2874  SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2875  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2876  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2877  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2878  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2879  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2880  )
2881 {
2882  int* locenergies;
2883  int* overlaps;
2884  int* idxs;
2885 
2886  SCIP_Longint requiredenergy;
2887  int v;
2888 
2889  SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2890  SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2891  SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2892 
2893  /* energy which needs be explained */
2894  requiredenergy = ((SCIP_Longint) end - begin) * capacity;
2895 
2896  SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %" SCIP_LONGINT_FORMAT ")\n", begin, end, capacity, requiredenergy);
2897 
2898  /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2899  * takes
2900  */
2901  for( v = 0; v < nvars; ++v )
2902  {
2903  SCIP_VAR* var;
2904  int glbenergy;
2905  int duration;
2906  int demand;
2907  int est;
2908  int lst;
2909 
2910  var = vars[v];
2911  assert(var != NULL);
2912 
2913  locenergies[v] = 0;
2914  overlaps[v] = 0;
2915  idxs[v] = v;
2916 
2917  demand = demands[v];
2918  assert(demand > 0);
2919 
2920  duration = durations[v];
2921  assert(duration > 0);
2922 
2923  /* check if the variable equals the inference variable (the one which was propagated) */
2924  if( infervar == var )
2925  {
2926  int overlap;
2927  int right;
2928  int left;
2929 
2930  assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2931 
2932  SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2933  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2934  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2935 
2936  /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2937  * which is necessary from the inference variable
2938  */
2939  if( boundtype == SCIP_BOUNDTYPE_UPPER )
2940  {
2941  int lct;
2942 
2943  /* get the latest start time of the infer start time variable before the propagation took place */
2944  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2945 
2946  /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2947  * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2948  * scheduled w.r.t. its latest start time
2949  */
2950  assert(lst < end);
2951 
2952  /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2953  * interval (before the propagation)
2954  */
2955  right = MIN3(end - lst, end - begin, duration);
2956 
2957  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2958  assert(right > 0);
2959 
2960  lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2961  assert(begin <= lct);
2962  assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
2963 
2964  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2965  left = MIN(lct - begin + 1, end - begin);
2966  assert(left > 0);
2967 
2968  /* compute the minimum overlap; */
2969  overlap = MIN(left, right);
2970  assert(overlap > 0);
2971  assert(overlap <= end - begin);
2972  assert(overlap <= duration);
2973 
2974  if( usebdwidening )
2975  {
2976  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2977  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2978  }
2979  else
2980  {
2981  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2982  }
2983  }
2984  else
2985  {
2986  int ect;
2987 
2988  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
2989 
2990  /* get the earliest completion time of the infer start time variable before the propagation took place */
2991  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2992 
2993  /* the earliest start time of the inference start time variable before the propagation needs to be larger as
2994  * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
2995  * the job is scheduled w.r.t. its earliest start time
2996  */
2997  assert(ect > begin);
2998 
2999  /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
3000  * interval (before the propagation)
3001  */
3002  left = MIN3(ect - begin, end - begin, duration);
3003 
3004  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
3005  assert(left > 0);
3006 
3007  est = SCIPconvertRealToInt(scip, relaxedbd);
3008  assert(end >= est);
3009  assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
3010 
3011  /* compute the overlap of the job after the propagation but considering the relaxed bound */
3012  right = MIN(end - est + 1, end - begin);
3013  assert(right > 0);
3014 
3015  /* compute the minimum overlap */
3016  overlap = MIN(left, right);
3017  assert(overlap > 0);
3018  assert(overlap <= end - begin);
3019  assert(overlap <= duration);
3020 
3021  if( usebdwidening )
3022  {
3023  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
3024  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
3025  }
3026  else
3027  {
3028  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
3029  }
3030  }
3031 
3032  /* subtract the amount of energy which is available due to the overlap of the inference start time */
3033  requiredenergy -= (SCIP_Longint) overlap * demand;
3034 
3035  if( explanation != NULL )
3036  explanation[v] = TRUE;
3037 
3038  continue;
3039  }
3040 
3041  /* global time points */
3042  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
3043  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
3044 
3045  glbenergy = 0;
3046 
3047  /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
3048  * time window
3049  */
3050  if( est + duration > begin && lst < end )
3051  {
3052  /* evaluated global contribution */
3053  glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
3054 
3055  /* remove the globally available energy form the required energy */
3056  requiredenergy -= glbenergy;
3057 
3058  if( explanation != NULL )
3059  explanation[v] = TRUE;
3060  }
3061 
3062  /* local time points */
3063  est = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
3064  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
3065 
3066  /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3067  * time window
3068  */
3069  if( est + duration > begin && lst < end )
3070  {
3071  overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3072 
3073  /* evaluated additionally local energy contribution */
3074  locenergies[v] = overlaps[v] * demand - glbenergy;
3075  assert(locenergies[v] >= 0);
3076  }
3077  }
3078 
3079  /* sort the variable contributions w.r.t. additional local energy contributions */
3080  SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3081 
3082  /* add local energy contributions until an overload is implied */
3083  for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3084  {
3085  SCIP_VAR* var;
3086  int duration;
3087  int overlap;
3088  int relaxlb;
3089  int relaxub;
3090  int idx;
3091 
3092  idx = idxs[v];
3093  assert(idx >= 0 && idx < nvars);
3094 
3095  var = vars[idx];
3096  assert(var != NULL);
3097  assert(var != infervar);
3098 
3099  duration = durations[idx];
3100  assert(duration > 0);
3101 
3102  overlap = overlaps[v];
3103  assert(overlap > 0);
3104 
3105  requiredenergy -= locenergies[v];
3106 
3107  if( requiredenergy < -1 )
3108  {
3109  int demand;
3110 
3111  demand = demands[idx];
3112  assert(demand > 0);
3113 
3114  overlap += (int)((requiredenergy + 1) / demand);
3115 
3116 #ifndef NDEBUG
3117  requiredenergy += locenergies[v];
3118  requiredenergy -= (SCIP_Longint) overlap * demand;
3119  assert(requiredenergy < 0);
3120 #endif
3121  }
3122  assert(overlap > 0);
3123 
3124  relaxlb = begin - duration + overlap;
3125  relaxub = end - overlap;
3126 
3127  SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3128  SCIPvarGetName(var),
3131  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var),
3132  relaxlb, relaxub, demands[idx], duration);
3133 
3134  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3135  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3136 
3137  if( explanation != NULL )
3138  explanation[idx] = TRUE;
3139  }
3140 
3141  assert(requiredenergy < 0);
3142 
3143  SCIPfreeBufferArray(scip, &idxs);
3144  SCIPfreeBufferArray(scip, &overlaps);
3145  SCIPfreeBufferArray(scip, &locenergies);
3146 
3147  return SCIP_OKAY;
3148 }
3149 
3150 /** resolve propagation w.r.t. the cumulative condition */
3151 static
3153  SCIP* scip, /**< SCIP data structure */
3154  int nvars, /**< number of start time variables (activities) */
3155  SCIP_VAR** vars, /**< array of start time variables */
3156  int* durations, /**< array of durations */
3157  int* demands, /**< array of demands */
3158  int capacity, /**< cumulative capacity */
3159  int hmin, /**< left bound of time axis to be considered (including hmin) */
3160  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3161  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3162  INFERINFO inferinfo, /**< the user information */
3163  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3164  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3165  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3166  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3167  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3168  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3169  )
3170 {
3171  switch( inferInfoGetProprule(inferinfo) )
3172  {
3173  case PROPRULE_1_CORETIMES:
3174  {
3175  int inferdemand;
3176  int inferduration;
3177  int inferpos;
3178  int inferpeak;
3179  int relaxedpeak;
3180  int provedpeak;
3181 
3182  /* get the position of the inferred variable in the vars array */
3183  inferpos = inferInfoGetData1(inferinfo);
3184  if( inferpos >= nvars || vars[inferpos] != infervar )
3185  {
3186  /* find inference variable in constraint */
3187  for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3188  {}
3189  }
3190  assert(inferpos < nvars);
3191  assert(vars[inferpos] == infervar);
3192 
3193  inferdemand = demands[inferpos];
3194  inferduration = durations[inferpos];
3195 
3196  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3197  {
3198  /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3199  * the inference variable
3200  */
3201  assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
3202 
3203  SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3204  SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
3205  SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3206 
3207  /* get the inference peak that the time point which lead to the that propagtion */
3208  inferpeak = inferInfoGetData2(inferinfo);
3209  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3210  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3211  */
3212  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3213  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) + inferduration;
3214 
3215  /* make sure that the relaxed peak is part of the effective horizon */
3216  relaxedpeak = MIN(relaxedpeak, hmax-1);
3217 
3218  /* make sure that relaxed peak is not larger than the infer peak
3219  *
3220  * This can happen in case the variable is not an active variable!
3221  */
3222  relaxedpeak = MAX(relaxedpeak, inferpeak);
3223  assert(relaxedpeak >= inferpeak);
3224  assert(relaxedpeak >= hmin);
3225  }
3226  else
3227  {
3228  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3229 
3230  SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3231  SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
3232  SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3233 
3234  /* get the time interval where the job could not be scheduled */
3235  inferpeak = inferInfoGetData2(inferinfo);
3236  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3237  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3238  */
3239  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3240  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) - 1;
3241 
3242  /* make sure that the relaxed peak is part of the effective horizon */
3243  relaxedpeak = MAX(relaxedpeak, hmin);
3244 
3245  /* make sure that relaxed peak is not larger than the infer peak
3246  *
3247  * This can happen in case the variable is not an active variable!
3248  */
3249  relaxedpeak = MIN(relaxedpeak, inferpeak);
3250  assert(relaxedpeak < hmax);
3251  }
3252 
3253  /* resolves the propagation of the core time algorithm */
3254  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3255  infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3256 
3257  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3258  {
3259  if( usebdwidening )
3260  {
3261  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3262  }
3263  else
3264  {
3265  /* old upper bound of variable itself is part of the explanation */
3266  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3267  }
3268  }
3269  else
3270  {
3271  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3272 
3273  if( usebdwidening )
3274  {
3275  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3276  }
3277  else
3278  {
3279  /* old lower bound of variable itself is part of the explanation */
3280  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3281  }
3282  }
3283 
3284  if( explanation != NULL )
3285  explanation[inferpos] = TRUE;
3286 
3287  break;
3288  }
3290  case PROPRULE_3_TTEF:
3291  {
3292  int begin;
3293  int end;
3294 
3295  begin = inferInfoGetData1(inferinfo);
3296  end = inferInfoGetData2(inferinfo);
3297  assert(begin < end);
3298 
3299  begin = MAX(begin, hmin);
3300  end = MIN(end, hmax);
3301 
3302  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3303  begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3304 
3305  break;
3306  }
3307 
3308  case PROPRULE_0_INVALID:
3309  default:
3310  SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3311  SCIPABORT();
3312  return SCIP_INVALIDDATA; /*lint !e527*/
3313  }
3314 
3315  (*result) = SCIP_SUCCESS;
3316 
3317  return SCIP_OKAY;
3318 }
3319 
3320 /**@} */
3321 
3322 
3323 /**@name Enforcement methods
3324  *
3325  * @{
3326  */
3327 
3328 /** apply all fixings which are given by the alternative bounds */
3329 static
3331  SCIP* scip, /**< SCIP data structure */
3332  SCIP_VAR** vars, /**< array of active variables */
3333  int nvars, /**< number of active variables */
3334  int* alternativelbs, /**< alternative lower bounds */
3335  int* alternativeubs, /**< alternative lower bounds */
3336  int* downlocks, /**< number of constraints with down lock participating by the computation */
3337  int* uplocks, /**< number of constraints with up lock participating by the computation */
3338  SCIP_Bool* branched /**< pointer to store if a branching was applied */
3339  )
3340 {
3341  int v;
3342 
3343  for( v = 0; v < nvars; ++v )
3344  {
3345  SCIP_VAR* var;
3346  SCIP_Real objval;
3347 
3348  var = vars[v];
3349  assert(var != NULL);
3350 
3351  objval = SCIPvarGetObj(var);
3352 
3353  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] && !SCIPisNegative(scip, objval) )
3354  {
3355  int ub;
3356 
3357  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3358 
3359  if( alternativelbs[v] <= ub )
3360  {
3361  SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3362  (*branched) = TRUE;
3363 
3364  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3365  SCIPvarGetLbLocal(var), alternativelbs[v]);
3366 
3367  return SCIP_OKAY;
3368  }
3369  }
3370 
3371  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] && !SCIPisPositive(scip, objval) )
3372  {
3373  int lb;
3374 
3375  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3376 
3377  if( alternativeubs[v] >= lb )
3378  {
3379  SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3380  (*branched) = TRUE;
3381 
3382  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3383  alternativeubs[v], SCIPvarGetUbLocal(var));
3384 
3385  return SCIP_OKAY;
3386  }
3387  }
3388  }
3389 
3390  return SCIP_OKAY;
3391 }
3392 
3393 /** remove the capacity requirments for all job which start at the curtime */
3394 static
3396  SCIP_CONSDATA* consdata, /**< constraint data */
3397  int curtime, /**< current point in time */
3398  int* starttimes, /**< array of start times */
3399  int* startindices, /**< permutation with respect to the start times */
3400  int* freecapacity, /**< pointer to store the resulting free capacity */
3401  int* idx, /**< pointer to index in start time array */
3402  int nvars /**< number of vars in array of starttimes and startindices */
3403  )
3404 {
3405 #if defined SCIP_DEBUG && !defined NDEBUG
3406  int oldidx;
3407 
3408  assert(idx != NULL);
3409  oldidx = *idx;
3410 #else
3411  assert(idx != NULL);
3412 #endif
3413 
3414  assert(starttimes != NULL);
3415  assert(starttimes != NULL);
3416  assert(freecapacity != NULL);
3417  assert(starttimes[*idx] == curtime);
3418  assert(consdata->demands != NULL);
3419  assert(freecapacity != idx);
3420 
3421  /* subtract all capacity needed up to this point */
3422  (*freecapacity) -= consdata->demands[startindices[*idx]];
3423 
3424  while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3425  {
3426  ++(*idx);
3427  (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3428  assert(freecapacity != idx);
3429  }
3430 #ifdef SCIP_DEBUG
3431  assert(oldidx <= *idx);
3432 #endif
3433 }
3434 
3435 /** add the capacity requirments for all job which end at the curtime */
3436 static
3437 void addEndingJobDemands(
3438  SCIP_CONSDATA* consdata, /**< constraint data */
3439  int curtime, /**< current point in time */
3440  int* endtimes, /**< array of end times */
3441  int* endindices, /**< permutation with rspect to the end times */
3442  int* freecapacity, /**< pointer to store the resulting free capacity */
3443  int* idx, /**< pointer to index in end time array */
3444  int nvars /**< number of vars in array of starttimes and startindices */
3445  )
3446 {
3447 #if defined SCIP_DEBUG && !defined NDEBUG
3448  int oldidx;
3449  oldidx = *idx;
3450 #endif
3451 
3452  /* free all capacity usages of jobs the are no longer running */
3453  while( endtimes[*idx] <= curtime && *idx < nvars)
3454  {
3455  (*freecapacity) += consdata->demands[endindices[*idx]];
3456  ++(*idx);
3457  }
3458 
3459 #ifdef SCIP_DEBUG
3460  assert(oldidx <= *idx);
3461 #endif
3462 }
3463 
3464 /** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3465 static
3467  SCIP* scip, /**< SCIP data structure */
3468  SCIP_CONSDATA* consdata, /**< constraint handler data */
3469  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3470  int* timepoint /**< pointer to store the time point of the peak */
3471  )
3472 {
3473  int* starttimes; /* stores when each job is starting */
3474  int* endtimes; /* stores when each job ends */
3475  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3476  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3477 
3478  int nvars; /* number of activities for this constraint */
3479  int freecapacity; /* remaining capacity */
3480  int curtime; /* point in time which we are just checking */
3481  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3482 
3483  int hmin;
3484  int hmax;
3485 
3486  int j;
3487 
3488  assert(consdata != NULL);
3489 
3490  nvars = consdata->nvars;
3491  assert(nvars > 0);
3492 
3493  *timepoint = consdata->hmax;
3494 
3495  assert(consdata->vars != NULL);
3496 
3497  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3498  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3499  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3500  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3501 
3502  /* create event point arrays */
3503  createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3504  starttimes, endtimes, startindices, endindices);
3505 
3506  endindex = 0;
3507  freecapacity = consdata->capacity;
3508  hmin = consdata->hmin;
3509  hmax = consdata->hmax;
3510 
3511  /* check each startpoint of a job whether the capacity is kept or not */
3512  for( j = 0; j < nvars; ++j )
3513  {
3514  curtime = starttimes[j];
3515  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3516 
3517  if( curtime >= hmax )
3518  break;
3519 
3520  /* remove the capacity requirments for all job which start at the curtime */
3521  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3522 
3523  /* add the capacity requirments for all job which end at the curtime */
3524  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3525 
3526  assert(freecapacity <= consdata->capacity);
3527  assert(endindex <= nvars);
3528 
3529  /* endindex - points to the next job which will finish */
3530  /* j - points to the last job that has been released */
3531 
3532  /* if free capacity is smaller than zero, then add branching candidates */
3533  if( freecapacity < 0 && curtime >= hmin )
3534  {
3535  *timepoint = curtime;
3536  break;
3537  }
3538  } /*lint --e{850}*/
3539 
3540  /* free all buffer arrays */
3541  SCIPfreeBufferArray(scip, &endindices);
3542  SCIPfreeBufferArray(scip, &startindices);
3543  SCIPfreeBufferArray(scip, &endtimes);
3544  SCIPfreeBufferArray(scip, &starttimes);
3545 
3546  return SCIP_OKAY;
3547 }
3548 
3549 /** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3550 static
3552  SCIP* scip, /**< SCIP data structure */
3553  SCIP_CONS** conss, /**< constraints to be processed */
3554  int nconss, /**< number of constraints */
3555  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3556  int* nbranchcands /**< pointer to store the number of branching variables */
3557  )
3558 {
3559  SCIP_HASHTABLE* collectedvars;
3560  int c;
3561 
3562  assert(scip != NULL);
3563  assert(conss != NULL);
3564 
3565  /* create a hash table */
3566  SCIP_CALL( SCIPhashtableCreate(&collectedvars, SCIPblkmem(scip), SCIPgetNVars(scip),
3567  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3568 
3569  assert(scip != NULL);
3570  assert(conss != NULL);
3571 
3572  for( c = 0; c < nconss; ++c )
3573  {
3574  SCIP_CONS* cons;
3575  SCIP_CONSDATA* consdata;
3576 
3577  int curtime;
3578  int j;
3579 
3580  cons = conss[c];
3581  assert(cons != NULL);
3582 
3583  if( !SCIPconsIsActive(cons) )
3584  continue;
3585 
3586  consdata = SCIPconsGetData(cons);
3587  assert(consdata != NULL);
3588 
3589  /* get point in time when capacity is exceeded */
3590  SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3591 
3592  if( curtime < consdata->hmin || curtime >= consdata->hmax )
3593  continue;
3594 
3595  /* report all variables that are running at that point in time */
3596  for( j = 0; j < consdata->nvars; ++j )
3597  {
3598  SCIP_VAR* var;
3599  int lb;
3600  int ub;
3601 
3602  var = consdata->vars[j];
3603  assert(var != NULL);
3604 
3605  /* check if the variable was already added */
3606  if( SCIPhashtableExists(collectedvars, (void*)var) )
3607  continue;
3608 
3609  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3610  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3611 
3612  if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3613  {
3614  SCIP_Real solval;
3615  SCIP_Real score;
3616 
3617  solval = SCIPgetSolVal(scip, sol, var);
3618  score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3619 
3620  SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3621  SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3622  (*nbranchcands)++;
3623 
3624  SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3625  }
3626  }
3627  }
3628 
3629  SCIPhashtableFree(&collectedvars);
3630 
3631  SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3632 
3633  return SCIP_OKAY;
3634 }
3635 
3636 /** enforcement of an LP, pseudo, or relaxation solution */
3637 static
3639  SCIP* scip, /**< SCIP data structure */
3640  SCIP_CONS** conss, /**< constraints to be processed */
3641  int nconss, /**< number of constraints */
3642  SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
3643  SCIP_Bool branch, /**< should branching candidates be collected */
3644  SCIP_RESULT* result /**< pointer to store the result */
3645  )
3646 {
3647  if( branch )
3648  {
3649  int nbranchcands;
3650 
3651  nbranchcands = 0;
3652  SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3653 
3654  if( nbranchcands > 0 )
3655  (*result) = SCIP_INFEASIBLE;
3656  }
3657  else
3658  {
3659  SCIP_Bool violated;
3660  int c;
3661 
3662  violated = FALSE;
3663 
3664  /* first check if a constraints is violated */
3665  for( c = 0; c < nconss && !violated; ++c )
3666  {
3667  SCIP_CONS* cons;
3668 
3669  cons = conss[c];
3670  assert(cons != NULL);
3671 
3672  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3673  }
3674 
3675  if( violated )
3676  (*result) = SCIP_INFEASIBLE;
3677  }
3678 
3679  return SCIP_OKAY;
3680 }
3681 
3682 /**@} */
3683 
3684 /**@name Propagation
3685  *
3686  * @{
3687  */
3688 
3689 /** check if cumulative constraint is independently of all other constraints */
3690 static
3692  SCIP_CONS* cons /**< cumulative constraint */
3693  )
3694 {
3695  SCIP_CONSDATA* consdata;
3696  SCIP_VAR** vars;
3697  SCIP_Bool* downlocks;
3698  SCIP_Bool* uplocks;
3699  int nvars;
3700  int v;
3701 
3702  consdata = SCIPconsGetData(cons);
3703  assert(consdata != NULL);
3704 
3705  nvars = consdata->nvars;
3706  vars = consdata->vars;
3707  downlocks = consdata->downlocks;
3708  uplocks = consdata->uplocks;
3709 
3710  /* check if the cumulative constraint has the only locks on the involved variables */
3711  for( v = 0; v < nvars; ++v )
3712  {
3713  SCIP_VAR* var;
3714 
3715  var = vars[v];
3716  assert(var != NULL);
3717 
3718  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
3719  || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
3720  return FALSE;
3721  }
3722 
3723  return TRUE;
3724 }
3725 
3726 /** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3727  * (dual reductions)
3728  */
3729 static
3731  SCIP* scip, /**< SCIP data structure */
3732  SCIP_CONS* cons, /**< cumulative constraint */
3733  SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3734  int* nchgbds, /**< pointer to store the number changed variable bounds */
3735  int* nfixedvars, /**< pointer to count number of fixings */
3736  int* ndelconss, /**< pointer to count number of deleted constraints */
3737  SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3738  SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3739  )
3740 {
3741  SCIP_CONSDATA* consdata;
3742  SCIP_VAR** vars;
3743  SCIP_Real* objvals;
3744  SCIP_Real* lbs;
3745  SCIP_Real* ubs;
3746  SCIP_Real timelimit;
3747  SCIP_Real memorylimit;
3748  SCIP_Bool solved;
3749  SCIP_Bool error;
3750 
3751  int ncheckconss;
3752  int nvars;
3753  int v;
3754 
3755  assert(scip != NULL);
3756  assert(!SCIPconsIsModifiable(cons));
3757  assert(SCIPgetNConss(scip) > 0);
3758 
3759  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3760  * would/could end in an implication which can lead to cutoff of the/all optimal solution
3761  */
3762  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
3763  return SCIP_OKAY;
3764 
3765  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3766  * use the locks to decide for a dual reduction using this constraint;
3767  */
3768  if( !SCIPconsIsChecked(cons) )
3769  return SCIP_OKAY;
3770 
3771  ncheckconss = SCIPgetNCheckConss(scip);
3772 
3773  /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3774  * presolved problem do nothing execpt to change the parameter settings
3775  */
3776  if( ncheckconss == 1 )
3777  {
3778  /* shrink the minimal maximum value for the conflict length */
3779  SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3780 
3781  /* use only first unique implication point */
3782  SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3783 
3784  /* do not use reconversion conflicts */
3785  SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3786 
3787  /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3788  SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3789 
3790  /* increase the number of conflicts which induce a restart */
3791  SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3792 
3793  /* weight the variable which made into a conflict */
3794  SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3795 
3796  /* do not check pseudo solution (for performance reasons) */
3797  SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3798 
3799  /* use value based history to detect a reasonable branching point */
3800  SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3801 
3802  /* turn of LP relaxation */
3803  SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3804 
3805  /* prefer the down branch in case the value based history does not suggest something */
3806  SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3807 
3808  /* accept any bound change */
3809  SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3810 
3811  /* allow for at most 10 restart, after that the value based history should be reliable */
3812  SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3813 
3814  /* set priority for depth first search to highest possible value */
3815  SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3816 
3817  return SCIP_OKAY;
3818  }
3819 
3820  consdata = SCIPconsGetData(cons);
3821  assert(consdata != NULL);
3822 
3823  /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3824  * fail on the first place
3825  */
3826  if( consdata->triedsolving )
3827  return SCIP_OKAY;
3828 
3829  /* check if constraint is independently */
3830  if( !isConsIndependently(cons) )
3831  return SCIP_OKAY;
3832 
3833  /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3834  * constraint is deleted; otherwise, we want to ensure that we do not try that again
3835  */
3836  consdata->triedsolving = TRUE;
3837 
3838  SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3839  SCIPconsGetName(cons), SCIPgetNVars(scip), SCIPgetNConss(scip));
3840  SCIPdebugPrintCons(scip, cons, NULL);
3841 
3842  nvars = consdata->nvars;
3843  vars = consdata->vars;
3844 
3845  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3846  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3847  SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3848 
3849  for( v = 0; v < nvars; ++v )
3850  {
3851  SCIP_VAR* var;
3852 
3853  /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3854  * array
3855  */
3856  var = vars[v];
3857  assert(var != NULL);
3858 
3859  lbs[v] = SCIPvarGetLbLocal(var);
3860  ubs[v] = SCIPvarGetUbLocal(var);
3861 
3862  objvals[v] = SCIPvarGetObj(var);
3863  }
3864 
3865  /* check whether there is enough time and memory left */
3866  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3867  if( !SCIPisInfinity(scip, timelimit) )
3868  timelimit -= SCIPgetSolvingTime(scip);
3869  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3870 
3871  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3872  if( !SCIPisInfinity(scip, memorylimit) )
3873  {
3874  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3875  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3876  }
3877 
3878  /* solve the cumulative condition separately */
3879  SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3880  consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3881 
3882  if( !(*cutoff) && !(*unbounded) && !error )
3883  {
3884  SCIP_Bool infeasible;
3885  SCIP_Bool tightened;
3886  SCIP_Bool allfixed;
3887 
3888  allfixed = TRUE;
3889 
3890  for( v = 0; v < nvars; ++v )
3891  {
3892  /* check if variable is fixed */
3893  if( lbs[v] + 0.5 > ubs[v] )
3894  {
3895  SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3896  assert(!infeasible);
3897 
3898  if( tightened )
3899  {
3900  (*nfixedvars)++;
3901  consdata->triedsolving = FALSE;
3902  }
3903  }
3904  else
3905  {
3906  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3907  assert(!infeasible);
3908 
3909  if( tightened )
3910  {
3911  (*nchgbds)++;
3912  consdata->triedsolving = FALSE;
3913  }
3914 
3915  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3916  assert(!infeasible);
3917 
3918  if( tightened )
3919  {
3920  (*nchgbds)++;
3921  consdata->triedsolving = FALSE;
3922  }
3923 
3924  allfixed = FALSE;
3925  }
3926  }
3927 
3928  /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3929  if( allfixed )
3930  {
3931  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3932  (*ndelconss)++;
3933  }
3934  }
3935 
3936  SCIPfreeBufferArray(scip, &objvals);
3937  SCIPfreeBufferArray(scip, &ubs);
3938  SCIPfreeBufferArray(scip, &lbs);
3939 
3940  return SCIP_OKAY;
3941 }
3942 
3943 /** start conflict analysis to analysis the core insertion which is infeasible */
3944 static
3946  SCIP* scip, /**< SCIP data structure */
3947  int nvars, /**< number of start time variables (activities) */
3948  SCIP_VAR** vars, /**< array of start time variables */
3949  int* durations, /**< array of durations */
3950  int* demands, /**< array of demands */
3951  int capacity, /**< cumulative capacity */
3952  int hmin, /**< left bound of time axis to be considered (including hmin) */
3953  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3954  SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3955  int inferduration, /**< duration of the start time variable */
3956  int inferdemand, /**< demand of the start time variable */
3957  int inferpeak, /**< profile preak which causes the infeasibilty */
3958  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3959  SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3960  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3961  )
3962 {
3963  SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3964  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3965  SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3966 
3967  /* initialize conflict analysis if conflict analysis is applicable */
3969  {
3971 
3972  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3973  infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3974 
3975  SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3976 
3977  /* add both bound of the inference variable since these biuld the core which we could not inserted */
3978  if( usebdwidening )
3979  {
3980  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
3981  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
3982  }
3983  else
3984  {
3985  SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
3986  SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
3987  }
3988 
3989  *initialized = TRUE;
3990  }
3991 
3992  return SCIP_OKAY;
3993 }
3994 
3995 /** We are using the core resource profile which contains all core except the one of the start time variable which we
3996  * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
3997  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
3998  * analysis
3999  */
4000 static
4002  SCIP* scip, /**< SCIP data structure */
4003  int nvars, /**< number of start time variables (activities) */
4004  SCIP_VAR** vars, /**< array of start time variables */
4005  int* durations, /**< array of durations */
4006  int* demands, /**< array of demands */
4007  int capacity, /**< cumulative capacity */
4008  int hmin, /**< left bound of time axis to be considered (including hmin) */
4009  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4010  SCIP_CONS* cons, /**< constraint which is propagated */
4011  SCIP_PROFILE* profile, /**< resource profile */
4012  int idx, /**< position of the variable to propagate */
4013  int* nchgbds, /**< pointer to store the number of bound changes */
4014  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
4015  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4016  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4017  SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
4018  )
4019 {
4020  SCIP_VAR* var;
4021  int ntimepoints;
4022  int duration;
4023  int demand;
4024  int peak;
4025  int newlb;
4026  int est;
4027  int lst;
4028  int pos;
4029 
4030  var = vars[idx];
4031  assert(var != NULL);
4032 
4033  duration = durations[idx];
4034  assert(duration > 0);
4035 
4036  demand = demands[idx];
4037  assert(demand > 0);
4038 
4039  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4040  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4041  ntimepoints = SCIPprofileGetNTimepoints(profile);
4042 
4043  /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
4044  * load which we have at the earliest start time (lower bound)
4045  */
4046  (void) SCIPprofileFindLeft(profile, est, &pos);
4047 
4048  SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
4049 
4050  /* we now trying to move the earliest start time in steps of at most "duration" length */
4051  do
4052  {
4053  INFERINFO inferinfo;
4054  SCIP_Bool tightened;
4055  int ect;
4056 
4057 #ifndef NDEBUG
4058  {
4059  /* in debug mode we check that we adjust the search position correctly */
4060  int tmppos;
4061 
4062  (void)SCIPprofileFindLeft(profile, est, &tmppos);
4063  assert(pos == tmppos);
4064  }
4065 #endif
4066  ect = est + duration;
4067  peak = -1;
4068 
4069  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4070  * want a peak which is closest to the earliest completion time
4071  */
4072  do
4073  {
4074  /* check if the profile load conflicts with the demand of the start time variable */
4075  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4076  peak = pos;
4077 
4078  pos++;
4079  }
4080  while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4081 
4082  /* if we found no peak that means current the job could be scheduled at its earliest start time without
4083  * conflicting to the core resource profile
4084  */
4085  /* coverity[check_after_sink] */
4086  if( peak == -1 )
4087  break;
4088 
4089  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4090  * profile. That means we have to move it to the next time point in the resource profile but at most to the
4091  * earliest completion time (the remaining move will done in the next loop)
4092  */
4093  newlb = SCIPprofileGetTime(profile, peak+1);
4094  newlb = MIN(newlb, ect);
4095 
4096  /* if the earliest start time is greater than the lst we detected an infeasibilty */
4097  if( newlb > lst )
4098  {
4099  SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4100 
4101  /* use conflict analysis to analysis the core insertion which was infeasible */
4102  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4103  var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4104 
4105  if( explanation != NULL )
4106  explanation[idx] = TRUE;
4107 
4108  *infeasible = TRUE;
4109 
4110  break;
4111  }
4112 
4113  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4114  * bound change
4115  */
4116  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4117 
4118  /* perform the bound lower bound change */
4119  if( inferInfoIsValid(inferinfo) )
4120  {
4121  SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4122  }
4123  else
4124  {
4125  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)newlb, TRUE, infeasible, &tightened) );
4126  }
4127  assert(tightened);
4128  assert(!(*infeasible));
4129 
4130  SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4131  (*nchgbds)++;
4132 
4133  /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4135 
4136  /* adjust the earliest start time
4137  *
4138  * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4139  * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4140  * involved.
4141  */
4142  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4143  assert(est >= newlb);
4144 
4145  /* adjust the search position for the resource profile for the next step */
4146  if( est == SCIPprofileGetTime(profile, peak+1) )
4147  pos = peak + 1;
4148  else
4149  pos = peak;
4150  }
4151  while( est < lst );
4152 
4153  return SCIP_OKAY;
4154 }
4155 
4156 /** We are using the core resource profile which contains all core except the one of the start time variable which we
4157  * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4158  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4159  * analysis
4160  */
4161 static
4163  SCIP* scip, /**< SCIP data structure */
4164  SCIP_VAR* var, /**< start time variable to propagate */
4165  int duration, /**< duration of the job */
4166  int demand, /**< demand of the job */
4167  int capacity, /**< cumulative capacity */
4168  SCIP_CONS* cons, /**< constraint which is propagated */
4169  SCIP_PROFILE* profile, /**< resource profile */
4170  int idx, /**< position of the variable to propagate */
4171  int* nchgbds /**< pointer to store the number of bound changes */
4172  )
4173 {
4174  int ntimepoints;
4175  int newub;
4176  int peak;
4177  int pos;
4178  int est;
4179  int lst;
4180  int lct;
4181 
4182  assert(var != NULL);
4183  assert(duration > 0);
4184  assert(demand > 0);
4185 
4186  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4187  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4188 
4189  /* in case the start time variable is fixed do nothing */
4190  if( est == lst )
4191  return SCIP_OKAY;
4192 
4193  ntimepoints = SCIPprofileGetNTimepoints(profile);
4194 
4195  lct = lst + duration;
4196 
4197  /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4198  * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4199  * position gives us the load which we have at the latest completion time minus one
4200  */
4201  (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4202 
4203  SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4204  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
4205 
4206  if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4207  return SCIP_OKAY;
4208 
4209  /* we now trying to move the latest start time in steps of at most "duration" length */
4210  do
4211  {
4212  INFERINFO inferinfo;
4213  SCIP_Bool tightened;
4214  SCIP_Bool infeasible;
4215 
4216  peak = -1;
4217 
4218 #ifndef NDEBUG
4219  {
4220  /* in debug mode we check that we adjust the search position correctly */
4221  int tmppos;
4222 
4223  (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4224  assert(pos == tmppos);
4225  }
4226 #endif
4227 
4228  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4229  * want a peak which is closest to the latest start time
4230  */
4231  do
4232  {
4233  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4234  peak = pos;
4235 
4236  pos--;
4237  }
4238  while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4239 
4240  /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4241  * to the core resource profile
4242  */
4243  /* coverity[check_after_sink] */
4244  if( peak == -1 )
4245  break;
4246 
4247  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4248  * profile. That means the job has be done until that point. Hence that gives us the latest completion
4249  * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4250  * doing in the next loop)
4251  */
4252  newub = SCIPprofileGetTime(profile, peak);
4253  newub = MAX(newub, lst) - duration;
4254  assert(newub >= est);
4255 
4256  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4257  * bound change
4258  */
4259  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4260 
4261  /* perform the bound upper bound change */
4262  if( inferInfoIsValid(inferinfo) )
4263  {
4264  SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4265  }
4266  else
4267  {
4268  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)newub, TRUE, &infeasible, &tightened) );
4269  }
4270  assert(tightened);
4271  assert(!infeasible);
4272 
4273  SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4274  (*nchgbds)++;
4275 
4276  /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4278 
4279  /* adjust the latest start and completion time
4280  *
4281  * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4282  * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4283  * involved.
4284  */
4285  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4286  assert(lst <= newub);
4287  lct = lst + duration;
4288 
4289  /* adjust the search position for the resource profile for the next step */
4290  if( SCIPprofileGetTime(profile, peak) == lct )
4291  pos = peak - 1;
4292  else
4293  pos = peak;
4294  }
4295  while( est < lst );
4296 
4297  return SCIP_OKAY;
4298 }
4299 
4300 /** compute for the different earliest start and latest completion time the core energy of the corresponding time
4301  * points
4302  */
4303 static
4305  SCIP_PROFILE* profile, /**< core profile */
4306  int nvars, /**< number of start time variables (activities) */
4307  int* ests, /**< array of sorted earliest start times */
4308  int* lcts, /**< array of sorted latest completion times */
4309  int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4310  int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4311  )
4312 {
4313  int ntimepoints;
4314  int energy;
4315  int t;
4316  int v;
4317 
4318  ntimepoints = SCIPprofileGetNTimepoints(profile);
4319  t = ntimepoints - 1;
4320  energy = 0;
4321 
4322  /* compute core energy after the earliest start time of each job */
4323  for( v = nvars-1; v >= 0; --v )
4324  {
4325  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4326  {
4327  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4328  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4329  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4330  t--;
4331  }
4332  assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4333 
4334  /* maybe ests[j] is in-between two timepoints */
4335  if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4336  {
4337  assert(t > 0);
4338  coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4339  }
4340  else
4341  coreEnergyAfterEst[v] = energy;
4342  }
4343 
4344  t = ntimepoints - 1;
4345  energy = 0;
4346 
4347  /* compute core energy after the latest completion time of each job */
4348  for( v = nvars-1; v >= 0; --v )
4349  {
4350  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4351  {
4352  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4353  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4354  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4355  t--;
4356  }
4357  assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4358 
4359  /* maybe lcts[j] is in-between two timepoints */
4360  if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4361  {
4362  assert(t > 0);
4363  coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4364  }
4365  else
4366  coreEnergyAfterLct[v] = energy;
4367  }
4368 }
4369 
4370 /** collect earliest start times, latest completion time, and free energy contributions */
4371 static
4372 void collectDataTTEF(
4373  SCIP* scip, /**< SCIP data structure */
4374  int nvars, /**< number of start time variables (activities) */
4375  SCIP_VAR** vars, /**< array of start time variables */
4376  int* durations, /**< array of durations */
4377  int* demands, /**< array of demands */
4378  int hmin, /**< left bound of time axis to be considered (including hmin) */
4379  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4380  int* permests, /**< array to store the variable positions */
4381  int* ests, /**< array to store earliest start times */
4382  int* permlcts, /**< array to store the variable positions */
4383  int* lcts, /**< array to store latest completion times */
4384  int* ects, /**< array to store earliest completion times of the flexible part of the job */
4385  int* lsts, /**< array to store latest start times of the flexible part of the job */
4386  int* flexenergies /**< array to store the flexible energies of each job */
4387  )
4388 {
4389  int v;
4390 
4391  for( v = 0; v < nvars; ++ v)
4392  {
4393  int duration;
4394  int leftadjust;
4395  int rightadjust;
4396  int core;
4397  int est;
4398  int lct;
4399  int ect;
4400  int lst;
4401 
4402  duration = durations[v];
4403  assert(duration > 0);
4404 
4405  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4406  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
4407  ect = est + duration;
4408  lct = lst + duration;
4409 
4410  ests[v] = est;
4411  lcts[v] = lct;
4412  permests[v] = v;
4413  permlcts[v] = v;
4414 
4415  /* compute core time window which lies within the effective horizon */
4416  core = (int) computeCoreWithInterval(hmin, hmax, ect, lst);
4417 
4418  /* compute the number of time steps the job could run before the effective horizon */
4419  leftadjust = MAX(0, hmin - est);
4420 
4421  /* compute the number of time steps the job could run after the effective horizon */
4422  rightadjust = MAX(0, lct - hmax);
4423 
4424  /* compute for each job the energy which is flexible; meaning not part of the core */
4425  flexenergies[v] = duration - leftadjust - rightadjust - core;
4426  flexenergies[v] = MAX(0, flexenergies[v]);
4427  flexenergies[v] *= demands[v];
4428  assert(flexenergies[v] >= 0);
4429 
4430  /* the earliest completion time of the flexible energy */
4431  ects[v] = MIN(ect, lst);
4432 
4433  /* the latest start time of the flexible energy */
4434  lsts[v] = MAX(ect, lst);
4435  }
4436 }
4437 
4438 /** try to tighten the lower bound of the given variable */
4439 static
4441  SCIP* scip, /**< SCIP data structure */
4442  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4443  int nvars, /**< number of start time variables (activities) */
4444  SCIP_VAR** vars, /**< array of start time variables */
4445  int* durations, /**< array of durations */
4446  int* demands, /**< array of demands */
4447  int capacity, /**< cumulative capacity */
4448  int hmin, /**< left bound of time axis to be considered (including hmin) */
4449  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4450  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4451  int duration, /**< duration of the job */
4452  int demand, /**< demand of the job */
4453  int est, /**< earliest start time of the job */
4454  int ect, /**< earliest completion time of the flexible part of the job */
4455  int lct, /**< latest completion time of the job */
4456  int begin, /**< begin of the time window under investigation */
4457  int end, /**< end of the time window under investigation */
4458  SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4459  int* bestlb, /**< pointer to strope the best lower bound change */
4460  int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4461  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4462  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4463  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4464  )
4465 {
4466  int newlb;
4467 
4468  assert(begin >= hmin);
4469  assert(end <= hmax);
4470 
4471  /* check if the time-table edge-finding should infer bounds */
4472  if( !conshdlrdata->ttefinfer )
4473  return SCIP_OKAY;
4474 
4475  /* if the job can be processed completely before or after the time window, nothing can be tightened */
4476  if( est >= end || ect <= begin )
4477  return SCIP_OKAY;
4478 
4479  /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4480  * skip since the overload check will do the job
4481  */
4482  if( est >= begin && ect <= end )
4483  return SCIP_OKAY;
4484 
4485  /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4486  * earliest start time
4487  */
4488  if( energy >= demand * ((SCIP_Longint) MAX(begin, est) - MIN(end, ect)) )
4489  return SCIP_OKAY;
4490 
4491  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4492  * present; therefore, we need to add the core;
4493  *
4494  * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4495  * compute the earliest completion time of the (whole) job
4496  */
4497  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4498 
4499  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4500  *
4501  * @note we can round down the compute duration w.r.t. the available energy
4502  */
4503  newlb = end - (int) (energy / demand);
4504 
4505  /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4506  * bound (latest start time); meaning it is not possible to schedule the job
4507  */
4508  if( newlb > lct - duration )
4509  {
4510  /* initialize conflict analysis if conflict analysis is applicable */
4512  {
4513  SCIP_Real relaxedbd;
4514 
4515  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4516 
4517  /* it is enough to overshoot the upper bound of the variable by one */
4518  relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4519 
4520  /* initialize conflict analysis */
4522 
4523  /* added to upper bound (which was overcut be new lower bound) of the variable */
4524  SCIP_CALL( SCIPaddConflictUb(scip, var, NULL) );
4525 
4526  /* analyze the infeasible */
4527  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4528  begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4529 
4530  (*initialized) = TRUE;
4531  }
4532 
4533  (*cutoff) = TRUE;
4534  }
4535  else if( newlb > (*bestlb) )
4536  {
4537  INFERINFO inferinfo;
4538 
4539  assert(newlb > begin);
4540 
4541  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4542 
4543  /* construct inference information */
4544  (*inferinfos) = inferInfoToInt(inferinfo);
4545  (*bestlb) = newlb;
4546  }
4547 
4548  return SCIP_OKAY;
4549 }
4550 
4551 /** try to tighten the upper bound of the given variable */
4552 static
4554  SCIP* scip, /**< SCIP data structure */
4555  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4556  int nvars, /**< number of start time variables (activities) */
4557  SCIP_VAR** vars, /**< array of start time variables */
4558  int* durations, /**< array of durations */
4559  int* demands, /**< array of demands */
4560  int capacity, /**< cumulative capacity */
4561  int hmin, /**< left bound of time axis to be considered (including hmin) */
4562  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4563  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4564  int duration, /**< duration of the job */
4565  int demand, /**< demand of the job */
4566  int est, /**< earliest start time of the job */
4567  int lst, /**< latest start time of the flexible part of the job */
4568  int lct, /**< latest completion time of the job */
4569  int begin, /**< begin of the time window under investigation */
4570  int end, /**< end of the time window under investigation */
4571  SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4572  int* bestub, /**< pointer to strope the best upper bound change */
4573  int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4574  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4575  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4576  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4577  )
4578 {
4579  int newub;
4580 
4581  assert(begin >= hmin);
4582  assert(end <= hmax);
4583  assert(est < begin);
4584 
4585  /* check if the time-table edge-finding should infer bounds */
4586  if( !conshdlrdata->ttefinfer )
4587  return SCIP_OKAY;
4588 
4589  /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4590  if( lst >= end || lct <= begin )
4591  return SCIP_OKAY;
4592 
4593  /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4594  * skip since the overload check will do the job
4595  */
4596  if( lst >= begin && lct <= end )
4597  return SCIP_OKAY;
4598 
4599  /* check if the available energy in the time window is to small to handle the flexible part of the job */
4600  if( energy >= demand * ((SCIP_Longint) MIN(end, lct) - MAX(begin, lst)) )
4601  return SCIP_OKAY;
4602 
4603  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4604  * present; therefore, we need to add the core;
4605  *
4606  * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4607  * latest start of the (whole) job
4608  */
4609  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4610  assert(energy >= 0);
4611 
4612  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4613  *
4614  * @note we can round down the compute duration w.r.t. the available energy
4615  */
4616  assert(demand > 0);
4617  newub = begin - duration + (int) (energy / demand);
4618 
4619  /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4620  * bound (earliest start time); meaning it is not possible to schedule the job
4621  */
4622  if( newub < est )
4623  {
4624  /* initialize conflict analysis if conflict analysis is applicable */
4626  {
4627  SCIP_Real relaxedbd;
4628 
4629  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4630 
4631  /* it is enough to undershoot the lower bound of the variable by one */
4632  relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4633 
4634  /* initialize conflict analysis */
4636 
4637  /* added to lower bound (which was undercut be new upper bound) of the variable */
4638  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
4639 
4640  /* analyze the infeasible */
4641  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4642  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4643 
4644  (*initialized) = TRUE;
4645  }
4646 
4647  (*cutoff) = TRUE;
4648  }
4649  else if( newub < (*bestub) )
4650  {
4651  INFERINFO inferinfo;
4652 
4653  assert(newub < begin);
4654 
4655  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4656 
4657  /* construct inference information */
4658  (*inferinfos) = inferInfoToInt(inferinfo);
4659  (*bestub) = newub;
4660  }
4661 
4662  return SCIP_OKAY;
4663 }
4664 
4665 /** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4666 static
4668  SCIP* scip, /**< SCIP data structure */
4669  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4670  int nvars, /**< number of start time variables (activities) */
4671  SCIP_VAR** vars, /**< array of start time variables */
4672  int* durations, /**< array of durations */
4673  int* demands, /**< array of demands */
4674  int capacity, /**< cumulative capacity */
4675  int hmin, /**< left bound of time axis to be considered (including hmin) */
4676  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4677  int* newlbs, /**< array to buffer new lower bounds */
4678  int* newubs, /**< array to buffer new upper bounds */
4679  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4680  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4681  int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4682  int* flexenergies, /**< array of flexible energies in the same order as the variables */
4683  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4684  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4685  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4686  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4687  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4688  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4689  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4690  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4691  )
4692 {
4693  int coreEnergyAfterEnd;
4694  SCIP_Longint maxavailable;
4695  SCIP_Longint minavailable;
4696  SCIP_Longint totalenergy;
4697  int nests;
4698  int est;
4699  int lct;
4700  int start;
4701  int end;
4702  int v;
4703 
4704  est = INT_MAX;
4705  lct = INT_MIN;
4706 
4707  /* compute earliest start and latest completion time of all jobs */
4708  for( v = 0; v < nvars; ++v )
4709  {
4710  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4711  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4712 
4713  est = MIN(est, start);
4714  lct = MAX(lct, end);
4715  }
4716 
4717  /* adjust the effective time horizon */
4718  hmin = MAX(hmin, est);
4719  hmax = MIN(hmax, lct);
4720 
4721  end = hmax + 1;
4722  coreEnergyAfterEnd = -1;
4723 
4724  maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
4725  minavailable = maxavailable;
4726  totalenergy = computeTotalEnergy(durations, demands, nvars);
4727 
4728  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4729  if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4730  return SCIP_OKAY;
4731 
4732  nests = nvars;
4733 
4734  /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4735  * times define the end of the time interval under investigation
4736  */
4737  for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4738  {
4739  int flexenergy;
4740  int minbegin;
4741  int lbenergy;
4742  int lbcand;
4743  int i;
4744 
4745  lct = lcts[v];
4746 
4747  /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4748  * infinity capacity is available; hence we skip that
4749  */
4750  if( lct > hmax )
4751  continue;
4752 
4753  /* if the latest completion time is smaller then hmin we have to stop */
4754  if( lct <= hmin )
4755  {
4756  assert(v == 0 || lcts[v-1] <= lcts[v]);
4757  break;
4758  }
4759 
4760  /* if the latest completion time equals to previous end time, we can continue since this particular interval
4761  * induced by end was just analyzed
4762  */
4763  if( lct == end )
4764  continue;
4765 
4766  assert(lct < end);
4767 
4768  /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4769  * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4770  * free energy; if so it means that in the next iterate the free-energy cannot be negative
4771  */
4772  if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4773  {
4774  SCIP_Longint freeenergy;
4775 
4776  assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4777  assert(coreEnergyAfterEnd >= 0);
4778 
4779  /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4780  freeenergy = capacity * ((SCIP_Longint) end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4781 
4782  if( freeenergy <= minavailable )
4783  {
4784  SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%" SCIP_LONGINT_FORMAT ">, free energy <%" SCIP_LONGINT_FORMAT ">)\n", lct, minavailable, freeenergy);
4785  continue;
4786  }
4787  }
4788 
4789  SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4790 
4791  end = lct;
4792  coreEnergyAfterEnd = coreEnergyAfterLct[v];
4793 
4794  flexenergy = 0;
4795  minavailable = maxavailable;
4796  minbegin = hmax;
4797  lbcand = -1;
4798  lbenergy = 0;
4799 
4800  /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4801  * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4802  * wider
4803  */
4804  for( i = nests-1; i >= 0; --i )
4805  {
4806  SCIP_VAR* var;
4807  SCIP_Longint freeenergy;
4808  int duration;
4809  int demand;
4810  int begin;
4811  int idx;
4812  int lst;
4813 
4814  idx = perm[i];
4815  assert(idx >= 0);
4816  assert(idx < nvars);
4817  assert(!(*cutoff));
4818 
4819  /* the earliest start time of the job */
4820  est = ests[i];
4821 
4822  /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4823  * latest completion times (which define end) are scant in non-increasing order
4824  */
4825  if( end <= est )
4826  {
4827  nests--;
4828  continue;
4829  }
4830 
4831  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4832  * current ending time
4833  */
4834  if( ((SCIP_Longint) end - est) * capacity >= totalenergy )
4835  break;
4836 
4837  var = vars[idx];
4838  assert(var != NULL);
4839 
4840  duration = durations[idx];
4841  assert(duration > 0);
4842 
4843  demand = demands[idx];
4844  assert(demand > 0);
4845 
4846  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4847 
4848  /* the latest start time of the free part of the job */
4849  lst = lsts[idx];
4850 
4851  /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4852  * investigation; hence the overload check will do the the job
4853  */
4854  assert(est <= minbegin);
4855  if( minavailable < maxavailable && est < minbegin )
4856  {
4857  assert(!(*cutoff));
4858 
4859  /* try to tighten the upper bound */
4860  SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4861  var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4862  initialized, explanation, cutoff) );
4863 
4864  if( *cutoff )
4865  break;
4866  }
4867 
4868  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4869  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4870 
4871  begin = est;
4872  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4873 
4874  /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4875  * free energy
4876  */
4877  if( begin < hmin )
4878  break;
4879 
4880  /* compute the contribution to the flexible energy */
4881  if( lct <= end )
4882  {
4883  /* if the jobs has to finish before the end, all the energy has to be scheduled */
4884  assert(lst >= begin);
4885  assert(flexenergies[idx] >= 0);
4886  flexenergy += flexenergies[idx];
4887  }
4888  else
4889  {
4890  /* the job partly overlaps with the end */
4891  int candenergy;
4892  int energy;
4893 
4894  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4895  * w.r.t. latest start time
4896  *
4897  * @note we need to be aware of the effective horizon
4898  */
4899  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4900  assert(end - lst < duration);
4901  assert(energy >= 0);
4902 
4903  /* adjust the flexible energy of the time interval */
4904  flexenergy += energy;
4905 
4906  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4907  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4908  assert(candenergy >= 0);
4909 
4910  /* check if we found a better candidate */
4911  if( candenergy > lbenergy )
4912  {
4913  lbenergy = candenergy;
4914  lbcand = idx;
4915  }
4916  }
4917 
4918  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4919  assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4920 
4921  /* compute the energy which is not used yet */
4922  freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4923 
4924  /* check overload */
4925  if( freeenergy < 0 )
4926  {
4927  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4928 
4929  /* initialize conflict analysis if conflict analysis is applicable */
4931  {
4932  /* analyze infeasibilty */
4934 
4935  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4936  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
4937  conshdlrdata->usebdwidening, explanation) );
4938 
4939  (*initialized) = TRUE;
4940  }
4941 
4942  (*cutoff) = TRUE;
4943 
4944  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4945  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
4946 
4947  break;
4948  }
4949 
4950  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4951  if( lbenergy > 0 && freeenergy < lbenergy )
4952  {
4953  SCIP_Longint energy;
4954  int newlb;
4955  int ect;
4956 
4957  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4958  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4959 
4960  /* remove the energy of our job from the ... */
4961  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) end - lsts[lbcand])) * demands[lbcand];
4962 
4963  newlb = end - (int)(energy / demands[lbcand]);
4964 
4965  if( newlb > lst )
4966  {
4967  /* initialize conflict analysis if conflict analysis is applicable */
4969  {
4970  SCIP_Real relaxedbd;
4971 
4972  /* analyze infeasibilty */
4974 
4975  relaxedbd = lst + 1.0;
4976 
4977  /* added to upper bound (which was overcut be new lower bound) of the variable */
4978  SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4979 
4980  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4981  begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
4982  conshdlrdata->usebdwidening, explanation) );
4983 
4984  (*initialized) = TRUE;
4985  }
4986 
4987  (*cutoff) = TRUE;
4988  break;
4989  }
4990  else if( newlb > newlbs[lbcand] )
4991  {
4992  INFERINFO inferinfo;
4993 
4994  /* construct inference information */
4995  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4996 
4997  /* buffer upper bound change */
4998  lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
4999  newlbs[lbcand] = newlb;
5000  }
5001  }
5002 
5003  /* check if the current interval has a smaller free energy */
5004  if( minavailable > freeenergy )
5005  {
5006  minavailable = freeenergy;
5007  minbegin = begin;
5008  }
5009  assert(minavailable >= 0);
5010  }
5011  }
5012 
5013  return SCIP_OKAY;
5014 }
5015 
5016 /** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
5017 static
5019  SCIP* scip, /**< SCIP data structure */
5020  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5021  int nvars, /**< number of start time variables (activities) */
5022  SCIP_VAR** vars, /**< array of start time variables */
5023  int* durations, /**< array of durations */
5024  int* demands, /**< array of demands */
5025  int capacity, /**< cumulative capacity */
5026  int hmin, /**< left bound of time axis to be considered (including hmin) */
5027  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5028  int* newlbs, /**< array to buffer new lower bounds */
5029  int* newubs, /**< array to buffer new upper bounds */
5030  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
5031  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
5032  int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
5033  int* flexenergies, /**< array of flexible energies in the same order as the variables */
5034  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
5035  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
5036  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
5037  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
5038  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
5039  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5040  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5041  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5042  )
5043 {
5044  int coreEnergyAfterStart;
5045  SCIP_Longint maxavailable;
5046  SCIP_Longint minavailable;
5047  SCIP_Longint totalenergy;
5048  int nlcts;
5049  int begin;
5050  int minest;
5051  int maxlct;
5052  int start;
5053  int end;
5054  int v;
5055 
5056  if( *cutoff )
5057  return SCIP_OKAY;
5058 
5059  begin = hmin - 1;
5060 
5061  minest = INT_MAX;
5062  maxlct = INT_MIN;
5063 
5064  /* compute earliest start and latest completion time of all jobs */
5065  for( v = 0; v < nvars; ++v )
5066  {
5067  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5068  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
5069 
5070  minest = MIN(minest, start);
5071  maxlct = MAX(maxlct, end);
5072  }
5073 
5074  /* adjust the effective time horizon */
5075  hmin = MAX(hmin, minest);
5076  hmax = MIN(hmax, maxlct);
5077 
5078  maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
5079  totalenergy = computeTotalEnergy(durations, demands, nvars);
5080 
5081  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5082  if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5083  return SCIP_OKAY;
5084 
5085  nlcts = 0;
5086 
5087  /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5088  * define the start of the time interval under investigation
5089  */
5090  for( v = 0; v < nvars; ++v )
5091  {
5092  int flexenergy;
5093  int minend;
5094  int ubenergy;
5095  int ubcand;
5096  int est;
5097  int i;
5098 
5099  est = ests[v];
5100 
5101  /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5102  * infinity capacity is available; hence we skip that
5103  */
5104  if( est < hmin )
5105  continue;
5106 
5107  /* if the earliest start time is larger or equal then hmax we have to stop */
5108  if( est >= hmax )
5109  break;
5110 
5111  /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5112  * induced by start was just analyzed
5113  */
5114  if( est == begin )
5115  continue;
5116 
5117  assert(est > begin);
5118 
5119  SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5120 
5121  begin = est;
5122  coreEnergyAfterStart = coreEnergyAfterEst[v];
5123 
5124  flexenergy = 0;
5125  minavailable = maxavailable;
5126  minend = hmin;
5127  ubcand = -1;
5128  ubenergy = 0;
5129 
5130  /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5131  * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5132  */
5133  for( i = nlcts; i < nvars; ++i )
5134  {
5135  SCIP_VAR* var;
5136  SCIP_Longint freeenergy;
5137  int duration;
5138  int demand;
5139  int idx;
5140  int lct;
5141  int ect;
5142 
5143  idx = perm[i];
5144  assert(idx >= 0);
5145  assert(idx < nvars);
5146  assert(!(*cutoff));
5147 
5148  /* the earliest start time of the job */
5149  lct = lcts[i];
5150 
5151  /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5152  * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5153  */
5154  if( lct <= begin )
5155  {
5156  nlcts++;
5157  continue;
5158  }
5159 
5160  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5161  * start with current beginning time
5162  */
5163  if( ((SCIP_Longint) lct - begin) * capacity >= totalenergy )
5164  break;
5165 
5166  var = vars[idx];
5167  assert(var != NULL);
5168 
5169  duration = durations[idx];
5170  assert(duration > 0);
5171 
5172  demand = demands[idx];
5173  assert(demand > 0);
5174 
5175  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5176 
5177  /* the earliest completion time of the flexible part of the job */
5178  ect = ects[idx];
5179 
5180  /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5181  * investigation; hence the overload check will do the the job
5182  */
5183  assert(lct >= minend);
5184  if( minavailable < maxavailable && lct > minend )
5185  {
5186  assert(!(*cutoff));
5187 
5188  /* try to tighten the upper bound */
5189  SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5190  var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5191  initialized, explanation, cutoff) );
5192 
5193  if( *cutoff )
5194  return SCIP_OKAY;
5195  }
5196 
5197  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5198  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5199 
5200  end = lct;
5201  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5202 
5203  /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5204  * free energy
5205  */
5206  if( end > hmax )
5207  break;
5208 
5209  /* compute the contribution to the flexible energy */
5210  if( est >= begin )
5211  {
5212  /* if the jobs has to finish before the end, all the energy has to be scheduled */
5213  assert(ect <= end);
5214  assert(flexenergies[idx] >= 0);
5215  flexenergy += flexenergies[idx];
5216  }
5217  else
5218  {
5219  /* the job partly overlaps with the end */
5220  int candenergy;
5221  int energy;
5222 
5223  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5224  * w.r.t. latest start time
5225  *
5226  * @note we need to be aware of the effective horizon
5227  */
5228  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5229  assert(ect - begin < duration);
5230  assert(energy >= 0);
5231 
5232  /* adjust the flexible energy of the time interval */
5233  flexenergy += energy;
5234 
5235  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5236  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5237  assert(candenergy >= 0);
5238 
5239  /* check if we found a better candidate */
5240  if( candenergy > ubenergy )
5241  {
5242  ubenergy = candenergy;
5243  ubcand = idx;
5244  }
5245  }
5246 
5247  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5248  assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5249 
5250  /* compute the energy which is not used yet */
5251  freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5252 
5253  /* check overload */
5254  if( freeenergy < 0 )
5255  {
5256  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5257 
5258  /* initialize conflict analysis if conflict analysis is applicable */
5260  {
5261  /* analyze infeasibilty */
5263 
5264  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5265  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
5266  conshdlrdata->usebdwidening, explanation) );
5267 
5268  (*initialized) = TRUE;
5269  }
5270 
5271  (*cutoff) = TRUE;
5272 
5273  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5274  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5275 
5276  return SCIP_OKAY;
5277  }
5278 
5279  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5280  if( ubenergy > 0 && freeenergy < ubenergy )
5281  {
5282  SCIP_Longint energy;
5283  int newub;
5284  int lst;
5285 
5286  duration = durations[ubcand];
5287  assert(duration > 0);
5288 
5289  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5290  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5291 
5292  /* remove the energy of our job from the ... */
5293  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) ects[ubcand] - begin)) * demands[ubcand];
5294 
5295  newub = begin - duration + (int)(energy / demands[ubcand]);
5296 
5297  if( newub < ect - duration )
5298  {
5299  /* initialize conflict analysis if conflict analysis is applicable */
5301  {
5302  SCIP_Real relaxedbd;
5303  /* analyze infeasibilty */
5305 
5306  relaxedbd = ect - duration - 1.0;
5307 
5308  /* added to lower bound (which was undercut be new upper bound) of the variable */
5309  SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5310 
5311  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5312  begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5313  conshdlrdata->usebdwidening, explanation) );
5314 
5315  (*initialized) = TRUE;
5316  }
5317 
5318  (*cutoff) = TRUE;
5319  return SCIP_OKAY;
5320  }
5321  else if( newub < newubs[ubcand] )
5322  {
5323  INFERINFO inferinfo;
5324 
5325  /* construct inference information */
5326  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5327 
5328  /* buffer upper bound change */
5329  ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5330  newubs[ubcand] = newub;
5331  }
5332  }
5333 
5334  /* check if the current interval has a smaller free energy */
5335  if( minavailable > freeenergy )
5336  {
5337  minavailable = freeenergy;
5338  minend = end;
5339  }
5340  assert(minavailable >= 0);
5341  }
5342  }
5343 
5344  return SCIP_OKAY;
5345 }
5346 
5347 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5348  * edge-finding
5349  *
5350  * @note The algorithm is based on the following two papers:
5351  * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5352  * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5353  * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5354  * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5355  * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5356  */
5357 static
5359  SCIP* scip, /**< SCIP data structure */
5360  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5361  SCIP_PROFILE* profile, /**< current core profile */
5362  int nvars, /**< number of start time variables (activities) */
5363  SCIP_VAR** vars, /**< array of start time variables */
5364  int* durations, /**< array of durations */
5365  int* demands, /**< array of demands */
5366  int capacity, /**< cumulative capacity */
5367  int hmin, /**< left bound of time axis to be considered (including hmin) */
5368  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5369  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5370  int* nchgbds, /**< pointer to store the number of bound changes */
5371  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5372  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5373  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5374  )
5375 {
5376  int* coreEnergyAfterEst;
5377  int* coreEnergyAfterLct;
5378  int* flexenergies;
5379  int* permests;
5380  int* permlcts;
5381  int* lcts;
5382  int* ests;
5383  int* ects;
5384  int* lsts;
5385 
5386  int* newlbs;
5387  int* newubs;
5388  int* lbinferinfos;
5389  int* ubinferinfos;
5390 
5391  int v;
5392 
5393  /* check if a cutoff was already detected */
5394  if( (*cutoff) )
5395  return SCIP_OKAY;
5396 
5397  /* check if at least the basic overload checking should be perfomed */
5398  if( !conshdlrdata->ttefcheck )
5399  return SCIP_OKAY;
5400 
5401  SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5402 
5403  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5404  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5405  SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5406  SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5407  SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5408  SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5409  SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5410  SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5411  SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5412 
5413  SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5414  SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5415  SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5416  SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5417 
5418  /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5419  for( v = 0; v < nvars; ++v )
5420  {
5421  newlbs[v] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5422  newubs[v] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5423  lbinferinfos[v] = 0;
5424  ubinferinfos[v] = 0;
5425  }
5426 
5427  /* collect earliest start times, latest completion time, and free energy contributions */
5428  collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5429 
5430  /* sort the earliest start times and latest completion in non-decreasing order */
5431  SCIPsortIntInt(ests, permests, nvars);
5432  SCIPsortIntInt(lcts, permlcts, nvars);
5433 
5434  /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5435  * points
5436  */
5437  computeCoreEnergyAfter(profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct);
5438 
5439  /* propagate the upper bounds and "opportunistically" the lower bounds */
5440  SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5441  newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5442  permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5443 
5444  /* propagate the lower bounds and "opportunistically" the upper bounds */
5445  SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5446  newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5447  permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5448 
5449  /* apply the buffer bound changes */
5450  for( v = 0; v < nvars && !(*cutoff); ++v )
5451  {
5452  SCIP_Bool infeasible;
5453  SCIP_Bool tightened;
5454 
5455  if( inferInfoIsValid(intToInferInfo(lbinferinfos[v])) )
5456  {
5457  SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v],
5458  TRUE, &infeasible, &tightened) );
5459  }
5460  else
5461  {
5462  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], (SCIP_Real)newlbs[v], TRUE, &infeasible, &tightened) );
5463  }
5464 
5465  /* since we change first the lower bound of the variable an infeasibilty should not be detected */
5466  assert(!infeasible);
5467 
5468  if( tightened )
5469  {
5470  (*nchgbds)++;
5471 
5472  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5474  }
5475 
5476  if( inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
5477  {
5478  SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v],
5479  TRUE, &infeasible, &tightened) );
5480  }
5481  else
5482  {
5483  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], (SCIP_Real)newubs[v], TRUE, &infeasible, &tightened) );
5484  }
5485 
5486  /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5487  * bound update can be infeasible
5488  */
5489  if( infeasible )
5490  {
5491  /* a small performance improvement is possible here: if the tighten...TEFF and propagate...TEFF methods would
5492  * return not only the inferinfos, but the actual begin and end values, then the infeasibility here could also
5493  * be analyzed in the case when begin and end exceed the 15 bit limit
5494  */
5495  if( SCIPisConflictAnalysisApplicable(scip) && inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
5496  {
5497  INFERINFO inferinfo;
5498  SCIP_VAR* var;
5499  int begin;
5500  int end;
5501 
5502  var = vars[v];
5503  assert(var != NULL);
5504 
5505  /* initialize conflict analysis */
5507 
5508  /* convert int to inference information */
5509  inferinfo = intToInferInfo(ubinferinfos[v]);
5510 
5511  /* collect time window from inference information */
5512  begin = inferInfoGetData1(inferinfo);
5513  end = inferInfoGetData2(inferinfo);
5514  assert(begin < end);
5515 
5516  /* added to lower bound (which was undercut be new upper bound) of the variable */
5517  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
5518 
5519  /* analysis the upper bound change */
5520  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5521  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5522  conshdlrdata->usebdwidening, explanation) );
5523 
5524  (*initialized) = TRUE;
5525  }
5526 
5527  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5528  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5529 
5530  (*cutoff) = TRUE;
5531  break;
5532  }
5533 
5534  if( tightened )
5535  {
5536  (*nchgbds)++;
5537 
5538  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5540  }
5541  }
5542 
5543  SCIPfreeBufferArray(scip, &ubinferinfos);
5544  SCIPfreeBufferArray(scip, &lbinferinfos);
5545  SCIPfreeBufferArray(scip, &newubs);
5546  SCIPfreeBufferArray(scip, &newlbs);
5547 
5548  /* free buffer arrays */
5549  SCIPfreeBufferArray(scip, &lsts);
5550  SCIPfreeBufferArray(scip, &ects);
5551  SCIPfreeBufferArray(scip, &ests);
5552  SCIPfreeBufferArray(scip, &lcts);
5553  SCIPfreeBufferArray(scip, &permests);
5554  SCIPfreeBufferArray(scip, &permlcts);
5555  SCIPfreeBufferArray(scip, &flexenergies);
5556  SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5557  SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5558 
5559  return SCIP_OKAY;
5560 }
5561 
5562 /** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5563  * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5564  * time table propagator
5565  */
5566 static
5568  SCIP* scip, /**< SCIP data structure */
5569  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5570  SCIP_PROFILE* profile, /**< core profile */
5571  int nvars, /**< number of start time variables (activities) */
5572  SCIP_VAR** vars, /**< array of start time variables */
5573  int* durations, /**< array of durations */
5574  int* demands, /**< array of demands */
5575  int capacity, /**< cumulative capacity */
5576  int hmin, /**< left bound of time axis to be considered (including hmin) */
5577  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5578  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5579  int* nchgbds, /**< pointer to store the number of bound changes */
5580  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5581  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5582  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5583  )
5584 {
5585  SCIP_Bool infeasible;
5586  int v;
5587 
5588  assert(scip != NULL);
5589  assert(nvars > 0);
5590  assert(cons != NULL);
5591  assert(cutoff != NULL);
5592 
5593  /* check if already a cutoff was detected */
5594  if( (*cutoff) )
5595  return SCIP_OKAY;
5596 
5597  /* check if the time tabling should infer bounds */
5598  if( !conshdlrdata->ttinfer )
5599  return SCIP_OKAY;
5600 
5601  assert(*initialized == FALSE);
5602 
5603  SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5604  SCIPconsGetName(cons), hmin, hmax, capacity);
5605 
5606  infeasible = FALSE;
5607 
5608  /* if core profile is empty; nothing to do */
5609  if( SCIPprofileGetNTimepoints(profile) <= 1 )
5610  return SCIP_OKAY;
5611 
5612  /* start checking each job whether the bounds can be improved */
5613  for( v = 0; v < nvars; ++v )
5614  {
5615  SCIP_VAR* var;
5616  int demand;
5617  int duration;
5618  int begin;
5619  int end;
5620  int est;
5621  int lst;
5622 
5623  var = vars[v];
5624  assert(var != NULL);
5625 
5626  duration = durations[v];
5627  assert(duration > 0);
5628 
5629  /* collect earliest and latest start time */
5630  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5631  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5632 
5633  /* check if the start time variables is already fixed; in that case we can ignore the job */
5634  if( est == lst )
5635  continue;
5636 
5637  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5638  if( lst + duration <= hmin || est >= hmax )
5639  continue;
5640 
5641  /* compute core interval w.r.t. effective time horizon */
5642  begin = MAX(hmin, lst);
5643  end = MIN(hmax, est + duration);
5644 
5645  demand = demands[v];
5646  assert(demand > 0);
5647 
5648  /* if the job has a core, remove it first */
5649  if( begin < end )
5650  {
5651  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5652  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5653 
5654  SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5655  }
5656 
5657  /* first try to update the earliest start time */
5658  SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5659  profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5660 
5661  if( *cutoff )
5662  break;
5663 
5664  /* second try to update the latest start time */
5665  SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5666  profile, v, nchgbds) );
5667 
5668  if( *cutoff )
5669  break;
5670 
5671  /* collect the potentially updated earliest and latest start time */
5672  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5673  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5674 
5675  /* compute core interval w.r.t. effective time horizon */
5676  begin = MAX(hmin, lst);
5677  end = MIN(hmax, est + duration);
5678 
5679  /* after updating the bound we might have a new core */
5680  if( begin < end )
5681  {
5682  int pos;
5683 
5684  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5685  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5686 
5687  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5688 
5689  if( infeasible )
5690  {
5691  /* use conflict analysis to analysis the core insertion which was infeasible */
5692  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5693  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5694 
5695  if( explanation != NULL )
5696  explanation[v] = TRUE;
5697 
5698  (*cutoff) = TRUE;
5699 
5700  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5701  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
5702 
5703  break;
5704  }
5705  }
5706  }
5707 
5708  return SCIP_OKAY;
5709 }
5710 
5711 
5712 /** node data structure for the binary tree used for edgefinding (with overload checking) */
5713 struct SCIP_NodeData
5714 {
5715  SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5716  SCIP_Real key; /**< key which is to insert the corresponding search node */
5717  int est; /**< earliest start time if the node data belongs to a leaf */
5718  int lct; /**< latest completion time if the node data belongs to a leaf */
5719  int demand; /**< demand of the job if the node data belongs to a leaf */
5720  int duration; /**< duration of the job if the node data belongs to a leaf */
5721  int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5722  int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5723  SCIP_Longint enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5724  int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5725  int energylambda;
5726  SCIP_Longint enveloplambda;
5727  int idx; /**< index of the start time variable in the (global) variable array */
5728  SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5729 };
5730 typedef struct SCIP_NodeData SCIP_NODEDATA;
5732 
5733 /** update node data structure starting from the given node along the path to the root node */
5734 static
5735 void updateEnvelope(
5736  SCIP* scip, /**< SCIP data structure */
5737  SCIP_BTNODE* node /**< search node which inserted */
5738  )
5739 {
5740  SCIP_BTNODE* left;
5741  SCIP_BTNODE* right;
5742  SCIP_NODEDATA* nodedata;
5743  SCIP_NODEDATA* leftdata;
5744  SCIP_NODEDATA* rightdata;
5745 
5746  SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5747 
5748  if( SCIPbtnodeIsLeaf(node) )
5749  node = SCIPbtnodeGetParent(node);
5750 
5751  while( node != NULL )
5752  {
5753  /* get node data */
5754  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5755  assert(nodedata != NULL);
5756 
5757  /* collect node data from left node */
5758  left = SCIPbtnodeGetLeftchild(node);
5759  assert(left != NULL);
5760  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5761  assert(leftdata != NULL);
5762 
5763  /* collect node data from right node */
5764  right = SCIPbtnodeGetRightchild(node);
5765  assert(right != NULL);
5766  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5767  assert(rightdata != NULL);
5768 
5769  /* update envelop and energy */
5770  if( leftdata->enveloptheta >= 0 )
5771  {
5772  assert(rightdata->energytheta != -1);
5773  nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5774  }
5775  else
5776  nodedata->enveloptheta = rightdata->enveloptheta;
5777 
5778  assert(leftdata->energytheta != -1);
5779  assert(rightdata->energytheta != -1);
5780  nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5781 
5782  if( leftdata->enveloplambda >= 0 )
5783  {
5784  assert(rightdata->energytheta != -1);
5785  nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5786  }
5787  else
5788  nodedata->enveloplambda = rightdata->enveloplambda;
5789 
5790  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5791  nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5792 
5793  SCIPdebugMsg(scip, "node <%p> lambda envelop %" SCIP_LONGINT_FORMAT "\n", (void*)node, nodedata->enveloplambda);
5794 
5795  if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5796  {
5797  assert(rightdata->energytheta != -1);
5798  assert(leftdata->energytheta != -1);
5799  nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5800  }
5801  else if( rightdata->energylambda >= 0 )
5802  {
5803  assert(leftdata->energytheta != -1);
5804  nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5805  }
5806  else if( leftdata->energylambda >= 0 )
5807  {
5808  assert(rightdata->energytheta != -1);
5809  nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5810  }
5811  else
5812  nodedata->energylambda = -1;
5813 
5814  /* go to parent */
5815  node = SCIPbtnodeGetParent(node);
5816  }
5817 
5818  SCIPdebugMsg(scip, "updating done\n");
5819 }
5820 
5821 /** updates the key of the first parent on the trace which comes from left */
5822 static
5823 void updateKeyOnTrace(
5824  SCIP_BTNODE* node, /**< node to start the trace */
5825  SCIP_Real key /**< update search key */
5826  )
5827 {
5828  assert(node != NULL);
5829 
5830  while( !SCIPbtnodeIsRoot(node) )
5831  {
5832  SCIP_BTNODE* parent;
5833 
5834  parent = SCIPbtnodeGetParent(node);
5835  assert(parent != NULL);
5836 
5837  if( SCIPbtnodeIsLeftchild(node) )
5838  {
5839  SCIP_NODEDATA* nodedata;
5840 
5841  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(parent);
5842  assert(nodedata != NULL);
5843 
5844  nodedata->key = key;
5845  return;
5846  }
5847 
5848  node = parent;
5849  }
5850 }
5851 
5852 
5853 /** deletes the given node and updates all envelops */
5854 static
5856  SCIP* scip, /**< SCIP data structure */
5857  SCIP_BT* tree, /**< binary tree */
5858  SCIP_BTNODE* node /**< node to be deleted */
5859  )
5860 {
5861  SCIP_BTNODE* parent;
5862  SCIP_BTNODE* grandparent;
5863  SCIP_BTNODE* sibling;
5864 
5865  assert(scip != NULL);
5866  assert(tree != NULL);
5867  assert(node != NULL);
5868 
5869  assert(SCIPbtnodeIsLeaf(node));
5870  assert(!SCIPbtnodeIsRoot(node));
5871 
5872  SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5873 
5874  parent = SCIPbtnodeGetParent(node);
5875  assert(parent != NULL);
5876  if( SCIPbtnodeIsLeftchild(node) )
5877  {
5878  sibling = SCIPbtnodeGetRightchild(parent);
5879  SCIPbtnodeSetRightchild(parent, NULL);
5880  }
5881  else
5882  {
5883  sibling = SCIPbtnodeGetLeftchild(parent);
5884  SCIPbtnodeSetLeftchild(parent, NULL);
5885  }
5886  assert(sibling != NULL);
5887 
5888  grandparent = SCIPbtnodeGetParent(parent);
5889 
5890  if( grandparent != NULL )
5891  {
5892  /* reset parent of sibling */
5893  SCIPbtnodeSetParent(sibling, grandparent);
5894 
5895  /* reset child of grandparent to sibling */
5896  if( SCIPbtnodeIsLeftchild(parent) )
5897  {
5898  SCIPbtnodeSetLeftchild(grandparent, sibling);
5899  }
5900  else
5901  {
5902  SCIP_NODEDATA* nodedata;
5903 
5904  assert(SCIPbtnodeIsRightchild(parent));
5905  SCIPbtnodeSetRightchild(grandparent, sibling);
5906 
5907  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(sibling);
5908 
5909  updateKeyOnTrace(grandparent, nodedata->key);
5910  }
5911 
5912  updateEnvelope(scip, grandparent);
5913  }
5914  else
5915  {
5916  SCIPbtnodeSetParent(sibling, NULL);
5917 
5918  SCIPbtSetRoot(tree, sibling);
5919  }
5920 
5921  SCIPbtnodeFree(tree, &parent);
5922 
5923  return SCIP_OKAY;
5924 }
5925 
5926 /** moves a node form the theta set into the lambda set and updates the envelops */
5927 static
5929  SCIP* scip, /**< SCIP data structure */
5930  SCIP_BT* tree, /**< binary tree */
5931  SCIP_BTNODE* node /**< node to move into the lambda set */
5932  )
5933 {
5934  SCIP_NODEDATA* nodedata;
5935 
5936  assert(scip != NULL);
5937  assert(tree != NULL);
5938  assert(node != NULL);
5939 
5940  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5941  assert(nodedata != NULL);
5942  assert(nodedata->intheta);
5943 
5944  /* move the contributions form the theta set into the lambda set */
5945  assert(nodedata->enveloptheta != -1);
5946  assert(nodedata->energytheta != -1);
5947  assert(nodedata->enveloplambda == -1);
5948  assert(nodedata->energylambda == -1);
5949  nodedata->enveloplambda = nodedata->enveloptheta;
5950  nodedata->energylambda = nodedata->energytheta;
5951 
5952  nodedata->enveloptheta = -1;
5953  nodedata->energytheta = 0;
5954  nodedata->intheta = FALSE;
5955 
5956  /* update the energy and envelop values on trace */
5957  updateEnvelope(scip, node);
5958 
5959  return SCIP_OKAY;
5960 }
5961 
5962 /** inserts a node into the theta set and update the envelops */
5963 static
5965  SCIP* scip, /**< SCIP data structure */
5966  SCIP_BT* tree, /**< binary tree */
5967  SCIP_BTNODE* node, /**< node to insert */
5968  SCIP_NODEDATA* nodedatas, /**< array of node data */
5969  int* nodedataidx, /**< array of indices for node data */
5970  int* nnodedatas /**< pointer to number of node data */
5971  )
5972 {
5973  /* if the tree is empty the node will be the root node */
5974  if( SCIPbtIsEmpty(tree) )
5975  {
5976  SCIPbtSetRoot(tree, node);
5977  }
5978  else
5979  {
5980  SCIP_NODEDATA* newnodedata;
5981  SCIP_NODEDATA* leafdata;
5982  SCIP_NODEDATA* nodedata;
5983  SCIP_BTNODE* leaf;
5984  SCIP_BTNODE* newnode;
5985  SCIP_BTNODE* parent;
5986 
5987  leaf = SCIPbtGetRoot(tree);
5988  assert(leaf != NULL);
5989 
5990  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
5991  assert(leafdata != NULL);
5992 
5993  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5994  assert(nodedata != NULL);
5995  assert(nodedata->intheta);
5996 
5997  /* find the position to insert the node */
5998  while( !SCIPbtnodeIsLeaf(leaf) )
5999  {
6000  if( nodedata->key < leafdata->key )
6001  leaf = SCIPbtnodeGetLeftchild(leaf);
6002  else
6003  leaf = SCIPbtnodeGetRightchild(leaf);
6004 
6005  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6006  assert(leafdata != NULL);
6007  }
6008 
6009  assert(leaf != NULL);
6010  assert(leaf != node);
6011 
6012  /* store node data to be able to delete them latter */
6013  newnodedata = &nodedatas[*nnodedatas];
6014  nodedataidx[*nnodedatas] = *nnodedatas;
6015  ++(*nnodedatas);
6016 
6017  /* init node data */
6018  newnodedata->var = NULL;
6019  newnodedata->key = SCIP_INVALID;
6020  newnodedata->est = INT_MIN;
6021  newnodedata->lct = INT_MAX;
6022  newnodedata->duration = 0;
6023  newnodedata->demand = 0;
6024  newnodedata->enveloptheta = -1;
6025  newnodedata->energytheta = 0;
6026  newnodedata->enveloplambda = -1;
6027  newnodedata->energylambda = -1;
6028  newnodedata->idx = -1;
6029  newnodedata->intheta = TRUE;
6030 
6031  /* create a new node */
6032  SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
6033  assert(newnode != NULL);
6034 
6035  parent = SCIPbtnodeGetParent(leaf);
6036 
6037  if( parent != NULL )
6038  {
6039  SCIPbtnodeSetParent(newnode, parent);
6040 
6041  /* check if the node is the left child */
6042  if( SCIPbtnodeGetLeftchild(parent) == leaf )
6043  {
6044  SCIPbtnodeSetLeftchild(parent, newnode);
6045  }
6046  else
6047  {
6048  SCIPbtnodeSetRightchild(parent, newnode);
6049  }
6050  }
6051  else
6052  SCIPbtSetRoot(tree, newnode);
6053 
6054  if( nodedata->key < leafdata->key )
6055  {
6056  /* node is on the left */
6057  SCIPbtnodeSetLeftchild(newnode, node);
6058  SCIPbtnodeSetRightchild(newnode, leaf);
6059  newnodedata->key = nodedata->key;
6060  }
6061  else
6062  {
6063  /* leaf is on the left */
6064  SCIPbtnodeSetLeftchild(newnode, leaf);
6065  SCIPbtnodeSetRightchild(newnode, node);
6066  newnodedata->key = leafdata->key;
6067  }
6068 
6069  SCIPbtnodeSetParent(leaf, newnode);
6070  SCIPbtnodeSetParent(node, newnode);
6071  }
6072 
6073  /* update envelop */
6074  updateEnvelope(scip, node);
6075 
6076  return SCIP_OKAY;
6077 }
6078 
6079 /** returns the leaf responsible for the lambda energy */
6080 static
6082  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6083  )
6084 {
6085  SCIP_BTNODE* left;
6086  SCIP_BTNODE* right;
6087  SCIP_NODEDATA* nodedata;
6088  SCIP_NODEDATA* leftdata;
6089  SCIP_NODEDATA* rightdata;
6090 
6091  assert(node != NULL);
6092 
6093  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6094  assert(nodedata != NULL);
6095 
6096  /* check if the node is the (responsible) leaf */
6097  if( SCIPbtnodeIsLeaf(node) )
6098  {
6099  assert(!nodedata->intheta);
6100  return node;
6101  }
6102 
6103  left = SCIPbtnodeGetLeftchild(node);
6104  assert(left != NULL);
6105 
6106  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6107  assert(leftdata != NULL);
6108 
6109  right = SCIPbtnodeGetRightchild(node);
6110  assert(right != NULL);
6111 
6112  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6113  assert(rightdata != NULL);
6114 
6115  assert(nodedata->energylambda != -1);
6116  assert(rightdata->energytheta != -1);
6117 
6118  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6120 
6121  assert(leftdata->energytheta != -1);
6122  assert(rightdata->energylambda != -1);
6123  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6124 
6126 }
6127 
6128 /** returns the leaf responsible for the lambda envelop */
6129 static
6131  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6132  )
6133 {
6134  SCIP_BTNODE* left;
6135  SCIP_BTNODE* right;
6136  SCIP_NODEDATA* nodedata;
6137  SCIP_NODEDATA* leftdata;
6138  SCIP_NODEDATA* rightdata;
6139 
6140  assert(node != NULL);
6141 
6142  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6143  assert(nodedata != NULL);
6144 
6145  /* check if the node is the (responsible) leaf */
6146  if( SCIPbtnodeIsLeaf(node) )
6147  {
6148  assert(!nodedata->intheta);
6149  return node;
6150  }
6151 
6152  left = SCIPbtnodeGetLeftchild(node);
6153  assert(left != NULL);
6154 
6155  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6156  assert(leftdata != NULL);
6157 
6158  right = SCIPbtnodeGetRightchild(node);
6159  assert(right != NULL);
6160 
6161  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6162  assert(rightdata != NULL);
6163 
6164  assert(nodedata->enveloplambda != -1);
6165  assert(rightdata->energytheta != -1);
6166 
6167  /* check if the left or right child is the one defining the envelop for the lambda set */
6168  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6170  else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6171  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6173 
6174  assert(rightdata->enveloplambda != -1);
6175  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6176 
6178 }
6179 
6180 
6181 /** reports all elements from set theta to generate a conflicting set */
6182 static
6183 void collectThetaSubtree(
6184  SCIP_BTNODE* node, /**< node within a theta subtree */
6185  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6186  int* nelements, /**< pointer to store the number of elements in omegaset */
6187  int* est, /**< pointer to store the earliest start time of the omega set */
6188  int* lct, /**< pointer to store the latest start time of the omega set */
6189  int* energy /**< pointer to store the energy of the omega set */
6190  )
6191 {
6192  SCIP_NODEDATA* nodedata;
6193 
6194  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6195  assert(nodedata != NULL);
6196 
6197  if( !SCIPbtnodeIsLeaf(node) )
6198  {
6199  collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6200  collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6201  }
6202  else if( nodedata->intheta )
6203  {
6204  assert(nodedata->var != NULL);
6205  SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6206 
6207  omegaset[*nelements] = node;
6208  (*est) = MIN(*est, nodedata->est);
6209  (*lct) = MAX(*lct, nodedata->lct);
6210  (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6211  (*nelements)++;
6212  }
6213 }
6214 
6215 
6216 /** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6217 static
6218 void traceThetaEnvelop(
6219  SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6220  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6221  int* nelements, /**< pointer to store the number of elements in omegaset */
6222  int* est, /**< pointer to store the earliest start time of the omega set */
6223  int* lct, /**< pointer to store the latest start time of the omega set */
6224  int* energy /**< pointer to store the energy of the omega set */
6225  )
6226 {
6227  assert(node != NULL);
6228 
6229  if( SCIPbtnodeIsLeaf(node) )
6230  {
6231  collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6232  }
6233  else
6234  {
6235  SCIP_BTNODE* left;
6236  SCIP_BTNODE* right;
6237  SCIP_NODEDATA* nodedata;
6238  SCIP_NODEDATA* leftdata;
6239  SCIP_NODEDATA* rightdata;
6240 
6241  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6242  assert(nodedata != NULL);
6243 
6244  left = SCIPbtnodeGetLeftchild(node);
6245  assert(left != NULL);
6246 
6247  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6248  assert(leftdata != NULL);
6249 
6250  right = SCIPbtnodeGetRightchild(node);
6251  assert(right != NULL);
6252 
6253  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6254  assert(rightdata != NULL);
6255 
6256  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6257  assert(nodedata != NULL);
6258 
6259  assert(nodedata->enveloptheta != -1);
6260  assert(rightdata->energytheta != -1);
6261 
6262  if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6263  {
6264  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6265  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6266  }
6267  else
6268  {
6269  assert(rightdata->enveloptheta != -1);
6270  assert(nodedata->enveloptheta == rightdata->enveloptheta);
6271  traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6272  }
6273  }
6274 }
6275 
6276 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6277 static
6278 void traceLambdaEnergy(
6279  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6280  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6281  int* nelements, /**< pointer to store the number of elements in omega set */
6282  int* est, /**< pointer to store the earliest start time of the omega set */
6283  int* lct, /**< pointer to store the latest start time of the omega set */
6284  int* energy /**< pointer to store the energy of the omega set */
6285  )
6286 {
6287  SCIP_BTNODE* left;
6288  SCIP_BTNODE* right;
6289  SCIP_NODEDATA* nodedata;
6290  SCIP_NODEDATA* leftdata;
6291  SCIP_NODEDATA* rightdata;
6292 
6293  assert(node != NULL);
6294 
6295  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6296  assert(nodedata != NULL);
6297 
6298  /* check if the node is a leaf */
6299  if( SCIPbtnodeIsLeaf(node) )
6300  return;
6301 
6302  left = SCIPbtnodeGetLeftchild(node);
6303  assert(left != NULL);
6304 
6305  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6306  assert(leftdata != NULL);
6307 
6308  right = SCIPbtnodeGetRightchild(node);
6309  assert(right != NULL);
6310 
6311  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6312  assert(rightdata != NULL);
6313 
6314  assert(nodedata->energylambda != -1);
6315  assert(rightdata->energytheta != -1);
6316 
6317  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6318  {
6319  traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6320  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6321  }
6322  else
6323  {
6324  assert(leftdata->energytheta != -1);
6325  assert(rightdata->energylambda != -1);
6326  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6327 
6328  collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6329  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6330  }
6331 }
6332 
6333 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6334 static
6335 void traceLambdaEnvelop(
6336  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6337  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6338  int* nelements, /**< pointer to store the number of elements in omega set */
6339  int* est, /**< pointer to store the earliest start time of the omega set */
6340  int* lct, /**< pointer to store the latest start time of the omega set */
6341  int* energy /**< pointer to store the energy of the omega set */
6342  )
6343 {
6344  SCIP_BTNODE* left;
6345  SCIP_BTNODE* right;
6346  SCIP_NODEDATA* nodedata;
6347  SCIP_NODEDATA* leftdata;
6348  SCIP_NODEDATA* rightdata;
6349 
6350  assert(node != NULL);
6351 
6352  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6353  assert(nodedata != NULL);
6354 
6355  /* check if the node is a leaf */
6356  if( SCIPbtnodeIsLeaf(node) )
6357  {
6358  assert(!nodedata->intheta);
6359  return;
6360  }
6361 
6362  left = SCIPbtnodeGetLeftchild(node);
6363  assert(left != NULL);
6364 
6365  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6366  assert(leftdata != NULL);
6367 
6368  right = SCIPbtnodeGetRightchild(node);
6369  assert(right != NULL);
6370 
6371  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6372  assert(rightdata != NULL);
6373 
6374  assert(nodedata->enveloplambda != -1);
6375  assert(rightdata->energytheta != -1);
6376 
6377  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6378  {
6379  traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6380  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6381  }
6382  else
6383  {
6384  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6385  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6386  {
6387  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6388  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6389  }
6390  else
6391  {
6392  assert(rightdata->enveloplambda != -1);
6393  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6394  traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6395  }
6396  }
6397 }
6398 
6399 /** compute the energy contribution by job which corresponds to the given leaf */
6400 static
6402  SCIP_BTNODE* node /**< leaf */
6403  )
6404 {
6405  SCIP_NODEDATA* nodedata;
6406  int duration;
6407 
6408  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6409  assert(nodedata != NULL);
6410  assert(nodedata->var != NULL);
6411 
6412  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6413  assert(duration > 0);
6414 
6415  SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6417  SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6418 
6419  /* return energy which is contributed by the start time variable */
6420  return nodedata->demand * duration;
6421 }
6422 
6423 /** comparison method for two node data w.r.t. the earliest start time */
6424 static
6425 SCIP_DECL_SORTPTRCOMP(compNodeEst)
6427  int est1;
6428  int est2;
6429 
6430  est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6431  est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6432 
6433  return (est1 - est2);
6434 }
6435 
6436 /** comparison method for two node data w.r.t. the latest completion time */
6437 static
6438 SCIP_DECL_SORTINDCOMP(compNodedataLct)
6440  SCIP_NODEDATA* nodedatas;
6441 
6442  nodedatas = (SCIP_NODEDATA*) dataptr;
6443  return (nodedatas[ind1].lct - nodedatas[ind2].lct);
6444 }
6445 
6446 
6447 /** an overload was detected; initialized conflict analysis, add an initial reason
6448  *
6449  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6450  */
6451 static
6453  SCIP* scip, /**< SCIP data structure */
6454  SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6455  int capacity, /**< cumulative capacity */
6456  int nleaves, /**< number of responsible leaves */
6457  int est, /**< earliest start time of the ...... */
6458  int lct, /**< latest completly time of the .... */
6459  int reportedenergy, /**< energy which already reported */
6460  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6461  int shift, /**< shift applied to all jobs before adding them to the tree */
6462  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6463  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6464  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6465  )
6466 {
6467  SCIP_Longint energy;
6468  int j;
6469 
6470  /* do nothing if conflict analysis is not applicable */
6472  return SCIP_OKAY;
6473 
6474  SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6475 
6476  /* compute energy of initial time window */
6477  energy = ((SCIP_Longint) lct - est) * capacity;
6478 
6479  /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6480  SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6481 
6482  /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6483  * thereby, compute the time window of interest
6484  */
6485  for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6486  {
6487  SCIP_NODEDATA* nodedata;
6488 
6489  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6490  assert(nodedata != NULL);
6491 
6492  reportedenergy += computeEnergyContribution(leaves[j]);
6493 
6494  /* adjust energy if the earliest start time decrease */
6495  if( nodedata->est < est )
6496  {
6497  est = nodedata->est;
6498  energy = ((SCIP_Longint) lct - est) * capacity;
6499  }
6500  }
6501  assert(reportedenergy > energy);
6502 
6503  SCIPdebugMsg(scip, "time window [%d,%d) available energy %" SCIP_LONGINT_FORMAT ", required energy %d\n", est, lct, energy, reportedenergy);
6504 
6505  /* initialize conflict analysis */
6507 
6508  /* flip earliest start time and latest completion time */
6509  if( !propest )
6510  {
6511  SCIPswapInts(&est, &lct);
6512 
6513  /* shift earliest start time and latest completion time */
6514  lct = shift - lct;
6515  est = shift - est;
6516  }
6517  else
6518  {
6519  /* shift earliest start time and latest completion time */
6520  lct = lct + shift;
6521  est = est + shift;
6522  }
6523 
6524  nleaves = j;
6525 
6526  /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6527  * overloaded
6528  */
6529  for( j = nleaves-1; j >= 0; --j )
6530  {
6531  SCIP_NODEDATA* nodedata;
6532 
6533  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6534  assert(nodedata != NULL);
6535  assert(nodedata->var != NULL);
6536 
6537  /* check if bound widening should be used */
6538  if( usebdwidening )
6539  {
6540  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6541  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6542  }
6543  else
6544  {
6545  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6546  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6547  }
6548 
6549  if( explanation != NULL )
6550  explanation[nodedata->idx] = TRUE;
6551  }
6552 
6553  (*initialized) = TRUE;
6554 
6555  return SCIP_OKAY;
6556 }
6557 
6558 /** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6559  * responsible interval bounds in *est_omega and *lct_omega
6560  */
6561 static
6562 int computeEstOmegaset(
6563  SCIP* scip, /**< SCIP data structure */
6564  int duration, /**< duration of the job to move */
6565  int demand, /**< demand of the job to move */
6566  int capacity, /**< cumulative capacity */
6567  int est, /**< earliest start time of the omega set */
6568  int lct, /**< latest start time of the omega set */
6569  int energy /**< energy of the omega set */
6570  )
6571 {
6572  int newest;
6573 
6574  newest = 0;
6575 
6576  assert(scip != NULL);
6577 
6578  if( energy > ((SCIP_Longint) capacity - demand) * ((SCIP_Longint) lct - est) )
6579  {
6580  if( energy + (SCIP_Longint) demand * duration > capacity * ((SCIP_Longint) lct - est) )
6581  {
6582  newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6583  newest += est;
6584  }
6585  }
6586 
6587  return newest;
6588 }
6589 
6590 /** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6591  *
6592  * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6593  * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6594  */
6595 static
6597  SCIP* scip, /**< SCIP data structure */
6598  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6599  SCIP_CONS* cons, /**< constraint which is propagated */
6600  SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6601  SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6602  int capacity, /**< cumulative capacity */
6603  int ncands, /**< number of candidates */
6604  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6605  int shift, /**< shift applied to all jobs before adding them to the tree */
6606  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6607  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6608  int* nchgbds, /**< pointer to store the number of bound changes */
6609  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6610  )
6611 {
6612  SCIP_NODEDATA* rootdata;
6613  int j;
6614 
6615  assert(!SCIPbtIsEmpty(tree));
6616 
6617  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6618  assert(rootdata != NULL);
6619 
6620  /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6621  for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6622  {
6623  SCIP_NODEDATA* nodedata;
6624 
6625  if( SCIPbtnodeIsRoot(leaves[j]) )
6626  break;
6627 
6628  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6629  assert(nodedata->est != -1);
6630 
6631  /* check if the root lambda envelop exeeds the available capacity */
6632  while( !(*cutoff) && rootdata->enveloplambda > (SCIP_Longint) capacity * nodedata->lct )
6633  {
6634  SCIP_BTNODE** omegaset;
6635  SCIP_BTNODE* leaf;
6636  SCIP_NODEDATA* leafdata;
6637  int nelements;
6638  int energy;
6639  int newest;
6640  int est;
6641  int lct;
6642 
6643  assert(!(*cutoff));
6644 
6645  /* find responsible leaf for the lambda envelope */
6647  assert(leaf != NULL);
6648  assert(SCIPbtnodeIsLeaf(leaf));
6649 
6650  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6651  assert(leafdata != NULL);
6652  assert(!leafdata->intheta);
6653  assert(leafdata->duration > 0);
6654  assert(leafdata->est >= 0);
6655 
6656  /* check if the job has to be removed since its latest completion is to large */
6657  if( leafdata->est + leafdata->duration >= nodedata->lct )
6658  {
6659  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6660 
6661  /* the root might changed therefore we need to collect the new root node data */
6662  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6663  assert(rootdata != NULL);
6664 
6665  continue;
6666  }
6667 
6668  /* compute omega set */
6669  SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6670 
6671  nelements = 0;
6672  est = INT_MAX;
6673  lct = INT_MIN;
6674  energy = 0;
6675 
6676  /* collect the omega set from theta set */
6677  traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6678  assert(nelements > 0);
6679  assert(nelements < ncands);
6680 
6681  newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6682 
6683  /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6684  if( newest > lct )
6685  {
6686  SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6687 
6688  /* analyze over load */
6689  SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6690  conshdlrdata->usebdwidening, initialized, explanation) );
6691  (*cutoff) = TRUE;
6692 
6693  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6694  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6695  }
6696  else if( newest > 0 )
6697  {
6698  SCIP_Bool infeasible;
6699  SCIP_Bool tightened;
6700  INFERINFO inferinfo;
6701 
6702  if( propest )
6703  {
6704  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6705  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6706 
6707  SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6708  SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6709 
6710  if( inferInfoIsValid(inferinfo) )
6711  {
6712  SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6713  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6714  }
6715  else
6716  {
6717  SCIP_CALL( SCIPtightenVarLb(scip, leafdata->var, (SCIP_Real)(newest + shift),
6718  TRUE, &infeasible, &tightened) );
6719  }
6720 
6721  /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6723  }
6724  else
6725  {
6726  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6727  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6728 
6729  SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6730  SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6731 
6732  if( inferInfoIsValid(inferinfo) )
6733  {
6734  SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6735  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6736  }
6737  else
6738  {
6739  SCIP_CALL( SCIPtightenVarUb(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6740  TRUE, &infeasible, &tightened) );
6741  }
6742 
6743  /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6745  }
6746 
6747  /* adjust the earliest start time */
6748  if( tightened )
6749  {
6750  leafdata->est = newest;
6751  (*nchgbds)++;
6752  }
6753 
6754  if( infeasible )
6755  {
6756  /* initialize conflict analysis if conflict analysis is applicable */
6758  {
6759  int i;
6760 
6761  SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6762 
6764 
6765  /* add lower and upper bound of variable which leads to the infeasibilty */
6766  SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6767  SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6768 
6769  if( explanation != NULL )
6770  explanation[leafdata->idx] = TRUE;
6771 
6772  /* add lower and upper bound of variable which lead to the infeasibilty */
6773  for( i = 0; i < nelements; ++i )
6774  {
6775  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6776  assert(nodedata != NULL);
6777 
6778  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6779  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6780 
6781  if( explanation != NULL )
6782  explanation[nodedata->idx] = TRUE;
6783  }
6784 
6785  (*initialized) = TRUE;
6786  }
6787 
6788  (*cutoff) = TRUE;
6789 
6790  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6791  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6792  }
6793  }
6794 
6795  /* free omegaset array */
6796  SCIPfreeBufferArray(scip, &omegaset);
6797 
6798  /* delete responsible leaf from lambda */
6799  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6800 
6801  /* the root might changed therefore we need to collect the new root node data */
6802  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6803  assert(rootdata != NULL);
6804  }
6805 
6806  /* move current job j from the theta set into the lambda set */
6807  SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6808  }
6809 
6810  return SCIP_OKAY;
6811 }
6812 
6813 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6814  *
6815  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6816  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6817  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6818  */
6819 static
6821  SCIP* scip, /**< SCIP data structure */
6822  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6823  int nvars, /**< number of start time variables (activities) */
6824  SCIP_VAR** vars, /**< array of start time variables */
6825  int* durations, /**< array of durations */
6826  int* demands, /**< array of demands */
6827  int capacity, /**< cumulative capacity */
6828  int hmin, /**< left bound of time axis to be considered (including hmin) */
6829  int hmax, /**< right bound of time axis to be considered (not including hmax) */
6830  SCIP_CONS* cons, /**< constraint which is propagated */
6831  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6832  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6833  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6834  int* nchgbds, /**< pointer to store the number of bound changes */
6835  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6836  )
6837 {
6838  SCIP_NODEDATA* nodedatas;
6839  SCIP_BTNODE** leaves;
6840  SCIP_BT* tree;
6841  int* nodedataidx;
6842 
6843  int totalenergy;
6844  int nnodedatas;
6845  int ninsertcands;
6846  int ncands;
6847 
6848  int shift;
6849  int idx = -1;
6850  int j;
6851 
6852  assert(scip != NULL);
6853  assert(cons != NULL);
6854  assert(initialized != NULL);
6855  assert(cutoff != NULL);
6856  assert(*cutoff == FALSE);
6857 
6858  SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6859 
6860  SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6861  SCIP_CALL( SCIPallocBufferArray(scip, &nodedataidx, 2*nvars) );
6862  SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6863 
6864  ncands = 0;
6865  totalenergy = 0;
6866 
6867  SCIP_CALL( SCIPbtCreate(&tree, SCIPblkmem(scip)) );
6868 
6869  /* compute the shift which we apply to compute .... latest completion time of all jobs */
6870  if( propest )
6871  shift = 0;
6872  else
6873  {
6874  shift = 0;
6875 
6876  /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6877  * earliest start time propagation to handle the latest completion times
6878  */
6879  for( j = 0; j < nvars; ++j )
6880  {
6881  int lct;
6882 
6883  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6884  shift = MAX(shift, lct);
6885  }
6886  }
6887 
6888  /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6889  * horizon
6890  */
6891  for( j = 0; j < nvars; ++j )
6892  {
6893  SCIP_NODEDATA* nodedata;
6894  SCIP_VAR* var;
6895  int duration;
6896  int leftadjust;
6897  int rightadjust;
6898  int energy;
6899  int est;
6900  int lct;
6901 
6902  var = vars[j];
6903  assert(var != NULL);
6904 
6905  duration = durations[j];
6906  assert(duration > 0);
6907 
6908  leftadjust = 0;
6909  rightadjust = 0;
6910 
6911  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
6912  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6913 
6914  /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6915  * effective horizon [hmin,hmax)
6916  */
6917  if( conshdlrdata->useadjustedjobs )
6918  {
6919  if( est < hmin )
6920  {
6921  leftadjust = (hmin - est);
6922  est = hmin;
6923  }
6924  if( lct > hmax )
6925  {
6926  rightadjust = (lct - hmax);
6927  lct = hmax;
6928  }
6929 
6930  /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6931  * with the effective time horizon
6932  */
6933  if( duration - leftadjust - rightadjust <= 0 )
6934  continue;
6935  }
6936  else if( est < hmin || lct > hmax )
6937  continue;
6938 
6939  energy = demands[j] * (duration - leftadjust - rightadjust);
6940  assert(energy > 0);
6941 
6942  totalenergy += energy;
6943 
6944  /* flip earliest start time and latest completion time */
6945  if( !propest )
6946  {
6947  SCIPswapInts(&est, &lct);
6948 
6949  /* shift earliest start time and latest completion time */
6950  lct = shift - lct;
6951  est = shift - est;
6952  }
6953  else
6954  {
6955  /* shift earliest start time and latest completion time */
6956  lct = lct - shift;
6957  est = est - shift;
6958  }
6959  assert(est < lct);
6960  assert(est >= 0);
6961  assert(lct >= 0);
6962 
6963  /* create search node data */
6964  nodedata = &nodedatas[ncands];
6965  nodedataidx[ncands] = ncands;
6966  ++ncands;
6967 
6968  /* initialize search node data */
6969  /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6970  nodedata->key = est + j / (2.0 * nvars);
6971  nodedata->var = var;
6972  nodedata->est = est;
6973  nodedata->lct = lct;
6974  nodedata->demand = demands[j];
6975  nodedata->duration = duration;
6976  nodedata->leftadjust = leftadjust;
6977  nodedata->rightadjust = rightadjust;
6978 
6979  /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6980  * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6981  * particular time interval [a,b] against the time interval [0,b].
6982  */
6983  nodedata->enveloptheta = (SCIP_Longint) capacity * est + energy;
6984  nodedata->energytheta = energy;
6985  nodedata->enveloplambda = -1;
6986  nodedata->energylambda = -1;
6987 
6988  nodedata->idx = j;
6989  nodedata->intheta = TRUE;
6990  }
6991 
6992  nnodedatas = ncands;
6993 
6994  /* sort (non-decreasing) the jobs w.r.t. latest completion times */
6995  SCIPsortInd(nodedataidx, compNodedataLct, (void*)nodedatas, ncands);
6996 
6997  ninsertcands = 0;
6998 
6999  /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
7000  * the root envelop detects an overload
7001  */
7002  for( j = 0; j < ncands; ++j )
7003  {
7004  SCIP_BTNODE* leaf;
7005  SCIP_NODEDATA* rootdata;
7006 
7007  idx = nodedataidx[j];
7008 
7009  /* check if the new job opens a time window which size is so large that it offers more energy than the total
7010  * energy of all candidate jobs. If so we skip that one.
7011  */
7012  if( ((SCIP_Longint) nodedatas[idx].lct - nodedatas[idx].est) * capacity >= totalenergy )
7013  {
7014  /* set the earliest start time to minus one to mark that candidate to be not used */
7015  nodedatas[idx].est = -1;
7016  continue;
7017  }
7018 
7019  /* create search node */
7020  SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)&nodedatas[idx]) );
7021 
7022  /* insert new node into the theta set and updete the envelops */
7023  SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, nodedataidx, &nnodedatas) );
7024  assert(nnodedatas <= 2*nvars);
7025 
7026  /* move the inserted candidates together */
7027  leaves[ninsertcands] = leaf;
7028  ninsertcands++;
7029 
7030  assert(!SCIPbtIsEmpty(tree));
7031  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
7032  assert(rootdata != NULL);
7033 
7034  /* check if the theta set envelops exceeds the available capacity */
7035  if( rootdata->enveloptheta > (SCIP_Longint) capacity * nodedatas[idx].lct )
7036  {
7037  SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[idx].lct, j);
7038  (*cutoff) = TRUE;
7039 
7040  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
7041  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverload++ );
7042 
7043  break;
7044  }
7045  }
7046 
7047  /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
7048  if( *cutoff )
7049  {
7050  int glbenery;
7051  int est;
7052  int lct;
7053 
7054  glbenery = 0;
7055  assert( 0 <= idx );
7056  est = nodedatas[idx].est;
7057  lct = nodedatas[idx].lct;
7058 
7059  /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
7060  * which led to an overload
7061  */
7062  for( j = j+1; j < ncands; ++j )
7063  {
7064  SCIP_NODEDATA* nodedata;
7065  int duration;
7066  int glbest;
7067  int glblct;
7068 
7069  idx = nodedataidx[j];
7070  nodedata = &nodedatas[idx];
7071  assert(nodedata != NULL);
7072 
7073  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
7074 
7075  /* get latest start time */
7076  glbest = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(nodedata->var));
7077  glblct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
7078 
7079  /* check if parts of the jobs run with the time window defined by the last inserted job */
7080  if( glbest < est )
7081  duration -= (est - glbest);
7082 
7083  if( glblct > lct )
7084  duration -= (glblct - lct);
7085 
7086  if( duration > 0 )
7087  {
7088  glbenery += nodedata->demand * duration;
7089 
7090  if( explanation != NULL )
7091  explanation[nodedata->idx] = TRUE;
7092  }
7093  }
7094 
7095  /* analyze the overload */
7096  SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7097  conshdlrdata->usebdwidening, initialized, explanation) );
7098  }
7099  else if( ninsertcands > 1 && conshdlrdata->efinfer )
7100  {
7101  /* if we have more than one job insterted and edge-finding should be performed we do it */
7102  SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7103  propest, shift, initialized, explanation, nchgbds, cutoff) );
7104  }
7105 
7106  /* free theta tree */
7107  SCIPbtFree(&tree);
7108 
7109  /* free buffer arrays */
7110  SCIPfreeBufferArray(scip, &leaves);
7111  SCIPfreeBufferArray(scip, &nodedataidx);
7112  SCIPfreeBufferArray(scip, &nodedatas);
7113 
7114  return SCIP_OKAY;
7115 }
7116 
7117 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7118  *
7119  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7120  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7121  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7122  */
7123 static
7125  SCIP* scip, /**< SCIP data structure */
7126  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7127  int nvars, /**< number of start time variables (activities) */
7128  SCIP_VAR** vars, /**< array of start time variables */
7129  int* durations, /**< array of durations */
7130  int* demands, /**< array of demands */
7131  int capacity, /**< cumulative capacity */
7132  int hmin, /**< left bound of time axis to be considered (including hmin) */
7133  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7134  SCIP_CONS* cons, /**< constraint which is propagated */
7135  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7136  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7137  int* nchgbds, /**< pointer to store the number of bound changes */
7138  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7139  )
7140 {
7141  /* check if a cutoff was already detected */
7142  if( (*cutoff) )
7143  return SCIP_OKAY;
7144 
7145  /* check if at least the basic overload checking should be preformed */
7146  if( !conshdlrdata->efcheck )
7147  return SCIP_OKAY;
7148 
7149  /* check for overload, which may result in a cutoff */
7150  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7151  cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7152 
7153  /* check if a cutoff was detected */
7154  if( (*cutoff) )
7155  return SCIP_OKAY;
7156 
7157  /* check if bound should be infer */
7158  if( !conshdlrdata->efinfer )
7159  return SCIP_OKAY;
7160 
7161  /* check for overload, which may result in a cutoff */
7162  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7163  cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7164 
7165  return SCIP_OKAY;
7166 }
7167 
7168 /** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7169  * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7170  * event points
7171  */
7172 static
7174  SCIP* scip, /**< SCIP data structure */
7175  int nvars, /**< number of start time variables (activities) */
7176  SCIP_VAR** vars, /**< array of start time variables */
7177  int* durations, /**< array of durations */
7178  int* demands, /**< array of demands */
7179  int capacity, /**< cumulative capacity */
7180  int hmin, /**< left bound of time axis to be considered (including hmin) */
7181  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7182  SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7183  )
7184 {
7185  SCIP_VAR* var;
7186  int* starttimes; /* stores when each job is starting */
7187  int* endtimes; /* stores when each job ends */
7188  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7189  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7190 
7191  int lb;
7192  int ub;
7193  int freecapacity; /* remaining capacity */
7194  int curtime; /* point in time which we are just checking */
7195  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7196  int njobs;
7197  int j;
7198 
7199  assert(scip != NULL);
7200  assert(redundant != NULL);
7201 
7202  (*redundant) = TRUE;
7203 
7204  /* if no activities are associated with this cumulative then this constraint is redundant */
7205  if( nvars == 0 )
7206  return SCIP_OKAY;
7207 
7208  assert(vars != NULL);
7209 
7210  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7211  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7212  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7213  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7214 
7215  njobs = 0;
7216 
7217  /* assign variables, start and endpoints to arrays */
7218  for( j = 0; j < nvars; ++j )
7219  {
7220  assert(durations[j] > 0);
7221  assert(demands[j] > 0);
7222 
7223  var = vars[j];
7224  assert(var != NULL);
7225 
7226  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7227  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7228 
7229  /* check if jobs runs completely outside of the effective time horizon */
7230  if( lb >= hmax || ub + durations[j] <= hmin )
7231  continue;
7232 
7233  starttimes[njobs] = MAX(lb, hmin);
7234  startindices[njobs] = j;
7235 
7236  endtimes[njobs] = MIN(ub + durations[j], hmax);
7237  endindices[njobs] = j;
7238  assert(starttimes[njobs] <= endtimes[njobs]);
7239  njobs++;
7240  }
7241 
7242  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7243  SCIPsortIntInt(starttimes, startindices, njobs);
7244  SCIPsortIntInt(endtimes, endindices, njobs);
7245 
7246  endindex = 0;
7247  freecapacity = capacity;
7248 
7249  /* check each start point of a job whether the capacity is violated or not */
7250  for( j = 0; j < njobs; ++j )
7251  {
7252  curtime = starttimes[j];
7253 
7254  /* stop checking, if time point is above hmax */
7255  if( curtime >= hmax )
7256  break;
7257 
7258  /* subtract all capacity needed up to this point */
7259  freecapacity -= demands[startindices[j]];
7260  while( j+1 < njobs && starttimes[j+1] == curtime )
7261  {
7262  ++j;
7263  freecapacity -= demands[startindices[j]];
7264  }
7265 
7266  /* free all capacity usages of jobs the are no longer running */
7267  while( endtimes[endindex] <= curtime )
7268  {
7269  freecapacity += demands[endindices[endindex]];
7270  ++endindex;
7271  }
7272  assert(freecapacity <= capacity);
7273 
7274  /* check freecapacity to be smaller than zero */
7275  if( freecapacity < 0 && curtime >= hmin )
7276  {
7277  (*redundant) = FALSE;
7278  break;
7279  }
7280  } /*lint --e{850}*/
7281 
7282  /* free all buffer arrays */
7283  SCIPfreeBufferArray(scip, &endindices);
7284  SCIPfreeBufferArray(scip, &startindices);
7285  SCIPfreeBufferArray(scip, &endtimes);
7286  SCIPfreeBufferArray(scip, &starttimes);
7287 
7288  return SCIP_OKAY;
7289 }
7290 
7291 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7292  * completion time
7293  */
7294 static
7296  SCIP* scip, /**< SCIP data structure */
7297  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7298  SCIP_PROFILE* profile, /**< resource profile */
7299  int nvars, /**< number of variables (jobs) */
7300  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7301  int* durations, /**< array containing corresponding durations */
7302  int* demands, /**< array containing corresponding demands */
7303  int capacity, /**< cumulative capacity */
7304  int hmin, /**< left bound of time axis to be considered (including hmin) */
7305  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7306  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7307  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7308  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7309  )
7310 {
7311  int v;
7312 
7313  /* insert all cores */
7314  for( v = 0; v < nvars; ++v )
7315  {
7316  SCIP_VAR* var;
7317  SCIP_Bool infeasible;
7318  int duration;
7319  int demand;
7320  int begin;
7321  int end;
7322  int est;
7323  int lst;
7324  int pos;
7325 
7326  var = vars[v];
7327  assert(var != NULL);
7328  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(var)));
7329  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(var)));
7330 
7331  duration = durations[v];
7332  assert(duration > 0);
7333 
7334  demand = demands[v];
7335  assert(demand > 0);
7336 
7337  /* collect earliest and latest start time */
7338  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7339  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7340 
7341  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7342  if( lst + duration <= hmin || est >= hmax )
7343  continue;
7344 
7345  /* compute core interval w.r.t. effective time horizon */
7346  begin = MAX(hmin, lst);
7347  end = MIN(hmax, est + duration);
7348 
7349  /* check if a core exists */
7350  if( begin >= end )
7351  continue;
7352 
7353  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7354  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7355 
7356  /* insert the core into core resource profile (complexity O(log n)) */
7357  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7358 
7359  /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7360  if( infeasible )
7361  {
7362  assert(begin <= SCIPprofileGetTime(profile, pos));
7363  assert(end > SCIPprofileGetTime(profile, pos));
7364 
7365  /* use conflict analysis to analysis the core insertion which was infeasible */
7366  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7367  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7368 
7369  if( explanation != NULL )
7370  explanation[v] = TRUE;
7371 
7372  (*cutoff) = TRUE;
7373 
7374  /* for the statistic we count the number of times a cutoff was detected due the time-time */
7375  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
7376 
7377  break;
7378  }
7379  }
7380 
7381  return SCIP_OKAY;
7382 }
7383 
7384 /** propagate the cumulative condition */
7385 static
7387  SCIP* scip, /**< SCIP data structure */
7388  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7389  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7390  int nvars, /**< number of start time variables (activities) */
7391  SCIP_VAR** vars, /**< array of start time variables */
7392  int* durations, /**< array of durations */
7393  int* demands, /**< array of demands */
7394  int capacity, /**< cumulative capacity */
7395  int hmin, /**< left bound of time axis to be considered (including hmin) */
7396  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7397  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7398  int* nchgbds, /**< pointer to store the number of bound changes */
7399  SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7400  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7401  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7402  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7403  )
7404 {
7405  SCIP_PROFILE* profile;
7406 
7407  SCIP_RETCODE retcode = SCIP_OKAY;
7408 
7409  assert(nchgbds != NULL);
7410  assert(initialized != NULL);
7411  assert(cutoff != NULL);
7412  assert(!(*cutoff));
7413 
7414  /**@todo avoid always sorting the variable array */
7415 
7416  /* check if the constraint is redundant */
7417  SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7418 
7419  if( *redundant )
7420  return SCIP_OKAY;
7421 
7422  /* create an empty resource profile for profiling the cores of the jobs */
7423  SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7424 
7425  /* create core profile (compulsory parts) */
7426  SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7427  initialized, explanation, cutoff), TERMINATE );
7428 
7429  /* propagate the job cores until nothing else can be detected */
7430  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7431  {
7432  SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7433  nchgbds, initialized, explanation, cutoff), TERMINATE );
7434  }
7435 
7436  /* run edge finding propagator */
7437  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7438  {
7439  SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7440  cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7441  }
7442 
7443  /* run time-table edge-finding propagator */
7444  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7445  {
7446  SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7447  nchgbds, initialized, explanation, cutoff), TERMINATE );
7448  }
7449  /* free resource profile */
7450 TERMINATE:
7451  SCIPprofileFree(&profile);
7452 
7453  return retcode;
7454 }
7455 
7456 /** propagate the cumulative constraint */
7457 static
7459  SCIP* scip, /**< SCIP data structure */
7460  SCIP_CONS* cons, /**< constraint to propagate */
7461  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7462  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7463  int* nchgbds, /**< pointer to store the number of bound changes */
7464  int* ndelconss, /**< pointer to store the number of deleted constraints */
7465  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7466  )
7467 {
7468  SCIP_CONSDATA* consdata;
7469  SCIP_Bool initialized;
7470  SCIP_Bool redundant;
7471  int oldnchgbds;
7472 
7473  assert(scip != NULL);
7474  assert(cons != NULL);
7475 
7476  consdata = SCIPconsGetData(cons);
7477  assert(consdata != NULL);
7478 
7479  oldnchgbds = *nchgbds;
7480  initialized = FALSE;
7481  redundant = FALSE;
7482 
7483  if( SCIPconsIsDeleted(cons) )
7484  {
7485  assert(SCIPinProbing(scip));
7486  return SCIP_OKAY;
7487  }
7488 
7489  /* if the constraint marked to be propagated, do nothing */
7490  if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7491  return SCIP_OKAY;
7492 
7493  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7494  consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7495  consdata->hmin, consdata->hmax, cons,
7496  nchgbds, &redundant, &initialized, NULL, cutoff) );
7497 
7498  if( redundant )
7499  {
7500  SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7501  SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7502 
7503  if( !SCIPinProbing(scip) )
7504  {
7505  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7506  (*ndelconss)++;
7507  }
7508  }
7509  else
7510  {
7511  if( initialized )
7512  {
7513  /* run conflict analysis since it was initialized */
7514  assert(*cutoff == TRUE);
7515  SCIPdebugMsg(scip, "start conflict analysis\n");
7516  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7517  }
7518 
7519  /* if successful, reset age of constraint */
7520  if( *cutoff || *nchgbds > oldnchgbds )
7521  {
7522  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7523  }
7524  else
7525  {
7526  /* mark the constraint to be propagated */
7527  consdata->propagated = TRUE;
7528  }
7529  }
7530 
7531  return SCIP_OKAY;
7532 }
7533 
7534 /** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7535  * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7536  * be realize as domain reduction. Otherwise we do nothing
7537  */
7538 static
7540  SCIP* scip, /**< SCIP data structure */
7541  SCIP_VAR** vars, /**< problem variables */
7542  int nvars, /**< number of problem variables */
7543  int probingpos, /**< variable number to apply probing on */
7544  SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7545  SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7546  SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7547  SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7548  SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7549  SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7550  SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7551  SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7552  SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7553  SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7554  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7555  SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7556  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7557  )
7558 {
7559  SCIP_VAR* var;
7560  SCIP_Bool tightened;
7561 
7562  assert(probingpos >= 0);
7563  assert(probingpos < nvars);
7564  assert(success != NULL);
7565  assert(cutoff != NULL);
7566 
7567  var = vars[probingpos];
7568  assert(var != NULL);
7569  assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7570  assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7571  assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7572  assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7573 
7574  (*success) = FALSE;
7575 
7576  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7577  return SCIP_OKAY;
7578 
7579  /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7580  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7581  leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7582 
7583  if( (*cutoff) )
7584  {
7585  /* note that cutoff may occur if presolving has not been executed fully */
7586  SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7587 
7588  if( tightened )
7589  {
7590  (*success) =TRUE;
7591  (*nfixedvars)++;
7592  }
7593 
7594  return SCIP_OKAY;
7595  }
7596 
7597  /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7598  * presolving has not been executed fully
7599  */
7600  if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7601  {
7602  /* note that cutoff may occur if presolving has not been executed fully */
7603  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7604 
7605  if( tightened )
7606  {
7607  (*success) = TRUE;
7608  (*nfixedvars)++;
7609  }
7610 
7611  return SCIP_OKAY;
7612  }
7613 
7614  /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7615  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7616  rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7617 
7618  if( (*cutoff) )
7619  {
7620  /* note that cutoff may occur if presolving has not been executed fully */
7621  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7622 
7623  if( tightened )
7624  {
7625  (*success) =TRUE;
7626  (*nfixedvars)++;
7627  }
7628 
7629  return SCIP_OKAY;
7630  }
7631 
7632  return SCIP_OKAY;
7633 }
7634 
7635 /** is it possible, to round variable down w.r.t. objective function */
7636 static
7638  SCIP* scip, /**< SCIP data structure */
7639  SCIP_VAR* var, /**< problem variable */
7640  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7641  )
7642 {
7643  SCIP_Real objval;
7644  int scalar;
7645 
7646  assert(roundable != NULL);
7647 
7648  *roundable = TRUE;
7649 
7650  /* a fixed variable can be definition always be safely rounded */
7652  return SCIP_OKAY;
7653 
7654  /* in case the variable is not active we need to check the object coefficient of the active variable */
7655  if( !SCIPvarIsActive(var) )
7656  {
7657  SCIP_VAR* actvar;
7658  int constant;
7659 
7660  actvar = var;
7661 
7662  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7663  assert(scalar != 0);
7664 
7665  objval = scalar * SCIPvarGetObj(actvar);
7666  } /*lint !e438*/
7667  else
7668  {
7669  scalar = 1;
7670  objval = SCIPvarGetObj(var);
7671  }
7672 
7673  /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7674  * (the transformed problem is always a minimization problem)
7675  *
7676  * @note that we need to check this condition w.r.t. active variable space
7677  */
7678  if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7679  *roundable = FALSE;
7680 
7681  return SCIP_OKAY;
7682 }
7683 
7684 /** is it possible, to round variable up w.r.t. objective function */
7685 static
7687  SCIP* scip, /**< SCIP data structure */
7688  SCIP_VAR* var, /**< problem variable */
7689  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7690  )
7691 {
7692  SCIP_Real objval;
7693  int scalar;
7694 
7695  assert(roundable != NULL);
7696 
7697  *roundable = TRUE;
7698 
7699  /* a fixed variable can be definition always be safely rounded */
7701  return SCIP_OKAY;
7702 
7703  /* in case the variable is not active we need to check the object coefficient of the active variable */
7704  if( !SCIPvarIsActive(var) )
7705  {
7706  SCIP_VAR* actvar;
7707  int constant;
7708 
7709  actvar = var;
7710 
7711  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7712  assert(scalar != 0);
7713 
7714  objval = scalar * SCIPvarGetObj(actvar);
7715  } /*lint !e438*/
7716  else
7717  {
7718  scalar = 1;
7719  objval = SCIPvarGetObj(var);
7720  }
7721 
7722  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7723  * (the transformed problem is always a minimization problem)
7724  *
7725  * @note that we need to check this condition w.r.t. active variable space
7726  */
7727  if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7728  *roundable = FALSE;
7729 
7730  return SCIP_OKAY;
7731 }
7732 
7733 /** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7734  * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7735  * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7736  * the only one locking this variable in the corresponding direction.
7737  */
7738 static
7740  SCIP* scip, /**< SCIP data structure */
7741  SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7742  int nconss, /**< number of cumulative constraints */
7743  SCIP_Bool local, /**< use local bounds effective horizon? */
7744  int* alternativelbs, /**< alternative lower bounds */
7745  int* alternativeubs, /**< alternative lower bounds */
7746  int* downlocks, /**< number of constraints with down lock participating by the computation */
7747  int* uplocks /**< number of constraints with up lock participating by the computation */
7748  )
7749 {
7750  int nvars;
7751  int c;
7752  int v;
7753 
7754  for( c = 0; c < nconss; ++c )
7755  {
7756  SCIP_CONSDATA* consdata;
7757  SCIP_CONS* cons;
7758  SCIP_VAR* var;
7759  int hmin;
7760  int hmax;
7761 
7762  cons = conss[c];
7763  assert(cons != NULL);
7764 
7765  /* ignore constraints which are already deletet and those which are not check constraints */
7766  if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7767  continue;
7768 
7769  consdata = SCIPconsGetData(cons);
7770  assert(consdata != NULL);
7771  assert(consdata->nvars > 1);
7772 
7773  /* compute the hmin and hmax */
7774  if( local )
7775  {
7776  SCIP_PROFILE* profile;
7777  SCIP_RETCODE retcode;
7778 
7779  /* create empty resource profile with infinity resource capacity */
7780  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7781 
7782  /* create worst case resource profile */
7783  retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
7784 
7785  hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7786  hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7787 
7788  /* free worst case profile */
7789  SCIPprofileFree(&profile);
7790 
7791  if( retcode != SCIP_OKAY )
7792  return retcode;
7793  }
7794  else
7795  {
7796  hmin = consdata->hmin;
7797  hmax = consdata->hmax;
7798  }
7799 
7800  consdata = SCIPconsGetData(cons);
7801  assert(consdata != NULL);
7802 
7803  nvars = consdata->nvars;
7804 
7805  for( v = 0; v < nvars; ++v )
7806  {
7807  int scalar;
7808  int constant;
7809  int idx;
7810 
7811  var = consdata->vars[v];
7812  assert(var != NULL);
7813 
7814  /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7815  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR);
7816 
7817  /* ignore variable locally fixed variables */
7818  if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7819  continue;
7820 
7821  SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7822  idx = SCIPvarGetProbindex(var);
7823  assert(idx >= 0);
7824 
7825  /* first check lower bound fixing */
7826  if( consdata->downlocks[v] )
7827  {
7828  int ect;
7829  int est;
7830 
7831  /* the variable has a down locked */
7832  est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7833  ect = est + consdata->durations[v];
7834 
7835  if( ect <= hmin || hmin >= hmax )
7836  downlocks[idx]++;
7837  else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7838  {
7839  alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7840  downlocks[idx]++;
7841  }
7842  }
7843 
7844  /* second check upper bound fixing */
7845  if( consdata->uplocks[v] )
7846  {
7847  int duration;
7848  int lct;
7849  int lst;
7850 
7851  duration = consdata->durations[v];
7852 
7853  /* the variable has a up lock locked */
7854  lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7855  lct = lst + duration;
7856 
7857  if( lst >= hmax || hmin >= hmax )
7858  uplocks[idx]++;
7859  else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7860  {
7861  alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7862  uplocks[idx]++;
7863  }
7864  }
7865  }
7866  }
7867 
7868  return SCIP_OKAY;
7869 }
7870 
7871 /** apply all fixings which are given by the alternative bounds */
7872 static
7874  SCIP* scip, /**< SCIP data structure */
7875  SCIP_VAR** vars, /**< array of active variables */
7876  int nvars, /**< number of active variables */
7877  int* alternativelbs, /**< alternative lower bounds */
7878  int* alternativeubs, /**< alternative lower bounds */
7879  int* downlocks, /**< number of constraints with down lock participating by the computation */
7880  int* uplocks, /**< number of constraints with up lock participating by the computation */
7881  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7882  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7883  )
7884 {
7885  SCIP_Real* downimpllbs;
7886  SCIP_Real* downimplubs;
7887  SCIP_Real* downproplbs;
7888  SCIP_Real* downpropubs;
7889  SCIP_Real* upimpllbs;
7890  SCIP_Real* upimplubs;
7891  SCIP_Real* upproplbs;
7892  SCIP_Real* uppropubs;
7893  int v;
7894 
7895  /* get temporary memory for storing probing results */
7896  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7897  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7898  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7899  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7900  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7901  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7902  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7903  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7904 
7905  for( v = 0; v < nvars; ++v )
7906  {
7907  SCIP_VAR* var;
7908  SCIP_Bool infeasible;
7909  SCIP_Bool fixed;
7910  SCIP_Bool roundable;
7911  int ub;
7912  int lb;
7913 
7914  var = vars[v];
7915  assert(var != NULL);
7916 
7917  /* ignore variables for which no alternative bounds have been computed */
7918  if( alternativelbs[v] == INT_MAX && alternativeubs[v] == INT_MIN )
7919  continue;
7920 
7921  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7922  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7923 
7924  /* ignore fixed variables */
7925  if( ub - lb <= 0 )
7926  continue;
7927 
7928  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
7929  {
7930  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7931 
7932  if( roundable )
7933  {
7934  if( alternativelbs[v] > ub )
7935  {
7936  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7937  assert(!infeasible);
7938  assert(fixed);
7939 
7940  (*nfixedvars)++;
7941 
7942  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7943  * constraints
7944  */
7945  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7946  }
7947  else
7948  {
7949  SCIP_Bool success;
7950 
7951  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7952  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7953  * infeasible we can apply the dual reduction; otherwise we do nothing
7954  */
7955  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7956  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7957  nfixedvars, &success, cutoff) );
7958 
7959  if( success )
7960  {
7961  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7962  }
7963  }
7964  }
7965  }
7966 
7967  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7968  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7969 
7970  /* ignore fixed variables */
7971  if( ub - lb <= 0 )
7972  continue;
7973 
7974  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
7975  {
7976  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7977 
7978  if( roundable )
7979  {
7980  if( alternativeubs[v] < lb )
7981  {
7982  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
7983  assert(!infeasible);
7984  assert(fixed);
7985 
7986  (*nfixedvars)++;
7987 
7988  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7989  * constraints
7990  */
7991  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7992  }
7993  else
7994  {
7995  SCIP_Bool success;
7996 
7997  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7998  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7999  * infeasible we can apply the dual reduction; otherwise we do nothing
8000  */
8001  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
8002  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
8003  nfixedvars, &success, cutoff) );
8004 
8005  if( success )
8006  {
8007  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
8008  }
8009  }
8010  }
8011  }
8012  }
8013 
8014  /* free temporary memory */
8015  SCIPfreeBufferArray(scip, &uppropubs);
8016  SCIPfreeBufferArray(scip, &upproplbs);
8017  SCIPfreeBufferArray(scip, &upimplubs);
8018  SCIPfreeBufferArray(scip, &upimpllbs);
8019  SCIPfreeBufferArray(scip, &downpropubs);
8020  SCIPfreeBufferArray(scip, &downproplbs);
8021  SCIPfreeBufferArray(scip, &downimplubs);
8022  SCIPfreeBufferArray(scip, &downimpllbs);
8023 
8024  return SCIP_OKAY;
8025 }
8026 
8027 /** propagate all constraints together */
8028 static
8030  SCIP* scip, /**< SCIP data structure */
8031  SCIP_CONS** conss, /**< all cumulative constraint */
8032  int nconss, /**< number of cumulative constraints */
8033  SCIP_Bool local, /**< use local bounds effective horizon? */
8034  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
8035  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
8036  SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
8037  )
8038 { /*lint --e{715}*/
8039  SCIP_VAR** vars;
8040  int* downlocks;
8041  int* uplocks;
8042  int* alternativelbs;
8043  int* alternativeubs;
8044  int oldnfixedvars;
8045  int nvars;
8046  int v;
8047 
8048  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
8049  return SCIP_OKAY;
8050 
8051  nvars = SCIPgetNVars(scip);
8052  oldnfixedvars = *nfixedvars;
8053 
8054  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
8055  SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
8056  SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
8057  SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
8058  SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
8059 
8060  /* initialize arrays */
8061  for( v = 0; v < nvars; ++v )
8062  {
8063  downlocks[v] = 0;
8064  uplocks[v] = 0;
8065  alternativelbs[v] = INT_MAX;
8066  alternativeubs[v] = INT_MIN;
8067  }
8068 
8069  /* compute alternative bounds */
8070  SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
8071 
8072  /* apply fixing which result of the alternative bounds directly */
8073  SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
8074  nfixedvars, cutoff) );
8075 
8076  if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
8077  {
8078  SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
8079  }
8080 
8081  /* free all buffers */
8082  SCIPfreeBufferArray(scip, &alternativeubs);
8083  SCIPfreeBufferArray(scip, &alternativelbs);
8084  SCIPfreeBufferArray(scip, &uplocks);
8085  SCIPfreeBufferArray(scip, &downlocks);
8086  SCIPfreeBufferArray(scip, &vars);
8087 
8088  return SCIP_OKAY;
8089 }
8090 
8091 /**@} */
8092 
8093 /**@name Linear relaxations
8094  *
8095  * @{
8096  */
8097 
8098 /** creates covering cuts for jobs violating resource constraints */
8099 static
8101  SCIP* scip, /**< SCIP data structure */
8102  SCIP_CONS* cons, /**< constraint to be checked */
8103  int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8104  int time /**< at this point in time covering constraints are valid */
8105  )
8106 {
8107  SCIP_CONSDATA* consdata;
8108  SCIP_ROW* row;
8109  int* flexibleids;
8110  int* demands;
8111 
8112  char rowname[SCIP_MAXSTRLEN];
8113 
8114  int remainingcap;
8115  int smallcoversize; /* size of a small cover */
8116  int bigcoversize; /* size of a big cover */
8117  int nvars;
8118 
8119  int nflexible;
8120  int sumdemand; /* demand of all jobs up to a certain index */
8121  int j;
8122 
8123  assert(cons != NULL);
8124 
8125  /* get constraint data structure */
8126  consdata = SCIPconsGetData(cons);
8127  assert(consdata != NULL );
8128 
8129  nvars = consdata->nvars;
8130 
8131  /* sort jobs according to demands */
8132  SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8133  SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8134 
8135  nflexible = 0;
8136  remainingcap = consdata->capacity;
8137 
8138  /* get all jobs intersecting point 'time' with their bounds */
8139  for( j = 0; j < nvars; ++j )
8140  {
8141  int ub;
8142 
8143  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8144 
8145  /* only add jobs to array if they intersect with point 'time' */
8146  if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8147  {
8148  /* if job is fixed, capacity has to be decreased */
8149  if( startvalues[j] == ub )
8150  {
8151  remainingcap -= consdata->demands[j];
8152  }
8153  else
8154  {
8155  demands[nflexible] = consdata->demands[j];
8156  flexibleids[nflexible] = j;
8157  ++nflexible;
8158  }
8159  }
8160  }
8161  assert(remainingcap >= 0);
8162 
8163  /* sort demands and job ids */
8164  SCIPsortIntInt(demands, flexibleids, nflexible);
8165 
8166  /*
8167  * version 1:
8168  * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8169  * erzeuge cover constraint
8170  *
8171  */
8172 
8173  /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8174  sumdemand = 0;
8175  j = 0;
8176 
8177  while( j < nflexible && sumdemand <= remainingcap )
8178  {
8179  sumdemand += demands[j];
8180  j++;
8181  }
8182 
8183  /* j jobs form a conflict, set coversize to 'j - 1' */
8184  bigcoversize = j-1;
8185  assert(sumdemand > remainingcap);
8186  assert(bigcoversize < nflexible);
8187 
8188  /* - create a row for all jobs and their binary variables.
8189  * - at most coversize many binary variables of jobs can be set to one
8190  */
8191 
8192  /* construct row name */
8193  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8194  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8195  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8196  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8197 
8198  for( j = 0; j < nflexible; ++j )
8199  {
8200  SCIP_VAR** binvars;
8201  SCIP_Real* vals;
8202  int nbinvars;
8203  int idx;
8204  int start;
8205  int end;
8206  int lb;
8207  int ub;
8208  int b;
8209 
8210  idx = flexibleids[j];
8211 
8212  /* get and add binvars into var array */
8213  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8214  assert(nbinvars != 0);
8215 
8216  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8217  assert(vals != NULL);
8218 
8219  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8220  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8221 
8222  /* compute start and finishing time */
8223  start = time - consdata->durations[idx] + 1;
8224  end = MIN(time, ub);
8225 
8226  /* add all neccessary binary variables */
8227  for( b = 0; b < nbinvars; ++b )
8228  {
8229  if( vals[b] < start || vals[b] < lb )
8230  continue;
8231 
8232  if( vals[b] > end )
8233  break;
8234 
8235  assert(binvars[b] != NULL);
8236  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8237  }
8238  }
8239 
8240  /* insert and release row */
8241  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8242 
8243  if( consdata->bcoverrowssize == 0 )
8244  {
8245  consdata->bcoverrowssize = 10;
8246  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8247  }
8248  if( consdata->nbcoverrows == consdata->bcoverrowssize )
8249  {
8250  consdata->bcoverrowssize *= 2;
8251  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8252  }
8253 
8254  consdata->bcoverrows[consdata->nbcoverrows] = row;
8255  consdata->nbcoverrows++;
8256 
8257  /*
8258  * version 2:
8259  * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8260  * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8261  */
8262  /* find maximum number of jobs that can run in parallel (= coversize -1) */
8263  sumdemand = 0;
8264  j = nflexible -1;
8265  while( sumdemand <= remainingcap )
8266  {
8267  assert(j >= 0);
8268  sumdemand += demands[j];
8269  j--;
8270  }
8271 
8272  smallcoversize = nflexible - (j + 1) - 1;
8273  while( j > 0 && demands[j] == demands[nflexible-1] )
8274  --j;
8275 
8276  assert(smallcoversize < nflexible);
8277 
8278  if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8279  {
8280  /* construct row name */
8281  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8282  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8283  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8284  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8285 
8286  /* filter binary variables for each unfixed job */
8287  for( j = j + 1; j < nflexible; ++j )
8288  {
8289  SCIP_VAR** binvars;
8290  SCIP_Real* vals;
8291  int nbinvars;
8292  int idx;
8293  int start;
8294  int end;
8295  int lb;
8296  int ub;
8297  int b;
8298 
8299  idx = flexibleids[j];
8300 
8301  /* get and add binvars into var array */
8302  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8303  assert(nbinvars != 0);
8304 
8305  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8306  assert(vals != NULL);
8307 
8308  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8309  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8310 
8311  /* compute start and finishing time */
8312  start = time - consdata->durations[idx] + 1;
8313  end = MIN(time, ub);
8314 
8315  /* add all neccessary binary variables */
8316  for( b = 0; b < nbinvars; ++b )
8317  {
8318  if( vals[b] < start || vals[b] < lb )
8319  continue;
8320 
8321  if( vals[b] > end )
8322  break;
8323 
8324  assert(binvars[b] != NULL);
8325  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8326  }
8327  }
8328 
8329  /* insert and release row */
8330  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8331  if( consdata->scoverrowssize == 0 )
8332  {
8333  consdata->scoverrowssize = 10;
8334  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8335  }
8336  if( consdata->nscoverrows == consdata->scoverrowssize )
8337  {
8338  consdata->scoverrowssize *= 2;
8339  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8340  }
8341 
8342  consdata->scoverrows[consdata->nscoverrows] = row;
8343  consdata->nscoverrows++;
8344  }
8345 
8346  /* free buffer arrays */
8347  SCIPfreeBufferArray(scip, &flexibleids);
8348  SCIPfreeBufferArray(scip, &demands);
8349 
8350  return SCIP_OKAY;
8351 }
8352 
8353 /** method to construct cover cuts for all points in time */
8354 static
8356  SCIP* scip, /**< SCIP data structure */
8357  SCIP_CONS* cons /**< constraint to be separated */
8358  )
8359 {
8360  SCIP_CONSDATA* consdata;
8361 
8362  int* startvalues; /* stores when each job is starting */
8363  int* endvalues; /* stores when each job ends */
8364  int* startvaluessorted; /* stores when each job is starting */
8365  int* endvaluessorted; /* stores when each job ends */
8366  int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8367  int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8368 
8369  int nvars; /* number of jobs for this constraint */
8370  int freecapacity; /* remaining capacity */
8371  int curtime; /* point in time which we are just checking */
8372  int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8373 
8374  int hmin;
8375  int hmax;
8376 
8377  int j;
8378  int t;
8379 
8380  assert(scip != NULL);
8381  assert(cons != NULL);
8382 
8383  consdata = SCIPconsGetData(cons);
8384  assert(consdata != NULL);
8385 
8386  /* if no activities are associated with this resource then this constraint is redundant */
8387  if( consdata->vars == NULL )
8388  return SCIP_OKAY;
8389 
8390  nvars = consdata->nvars;
8391  hmin = consdata->hmin;
8392  hmax = consdata->hmax;
8393 
8394  SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8395  SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8396  SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8397  SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8398  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8399  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8400 
8401  /* assign start and endpoints to arrays */
8402  for ( j = 0; j < nvars; ++j )
8403  {
8404  startvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8405  startvaluessorted[j] = startvalues[j];
8406 
8407  endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8408  endvaluessorted[j] = endvalues[j];
8409 
8410  startindices[j] = j;
8411  endindices[j] = j;
8412  }
8413 
8414  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8415  * (and sort the indices in the same way) */
8416  SCIPsortIntInt(startvaluessorted, startindices, nvars);
8417  SCIPsortIntInt(endvaluessorted, endindices, nvars);
8418 
8419  endidx = 0;
8420  freecapacity = consdata->capacity;
8421 
8422  /* check each startpoint of a job whether the capacity is kept or not */
8423  for( j = 0; j < nvars; ++j )
8424  {
8425  curtime = startvaluessorted[j];
8426  if( curtime >= hmax )
8427  break;
8428 
8429  /* subtract all capacity needed up to this point */
8430  freecapacity -= consdata->demands[startindices[j]];
8431 
8432  while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8433  {
8434  ++j;
8435  freecapacity -= consdata->demands[startindices[j]];
8436  }
8437 
8438  /* free all capacity usages of jobs the are no longer running */
8439  while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8440  {
8441  freecapacity += consdata->demands[endindices[endidx]];
8442  ++endidx;
8443  }
8444 
8445  assert(freecapacity <= consdata->capacity);
8446  assert(endidx <= nvars);
8447 
8448  /* --> endindex - points to the next job which will finish
8449  * j - points to the last job that has been released
8450  */
8451 
8452  /* check freecapacity to be smaller than zero
8453  * then we will add cover constraints to the MIP
8454  */
8455  if( freecapacity < 0 && curtime >= hmin )
8456  {
8457  int nextprofilechange;
8458 
8459  /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8460  if( j < nvars-1 )
8461  nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8462  else
8463  nextprofilechange = endvaluessorted[endidx];
8464 
8465  nextprofilechange = MIN(nextprofilechange, hmax);
8466 
8467  for( t = curtime; t < nextprofilechange; ++t )
8468  {
8469  SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8470 
8471  /* create covering constraint */
8472  SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8473  }
8474  } /* end if freecapacity > 0 */
8475  } /*lint --e{850}*/
8476 
8477  consdata->covercuts = TRUE;
8478 
8479  /* free all buffer arrays */
8480  SCIPfreeBufferArray(scip, &endindices);
8481  SCIPfreeBufferArray(scip, &startindices);
8482  SCIPfreeBufferArray(scip, &endvaluessorted);
8483  SCIPfreeBufferArray(scip, &startvaluessorted);
8484  SCIPfreeBufferArray(scip, &endvalues);
8485  SCIPfreeBufferArray(scip, &startvalues);
8486 
8487  return SCIP_OKAY;
8488 }
8489 
8490 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8491  * constraint
8492  */
8493 static
8495  SCIP* scip, /**< SCIP data structure */
8496  SCIP_CONS* cons, /**< constraint to be checked */
8497  int* startindices, /**< permutation with rspect to the start times */
8498  int curtime, /**< current point in time */
8499  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8500  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8501  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8502  )
8503 {
8504  SCIP_CONSDATA* consdata;
8505  SCIP_VAR** binvars;
8506  int* coefs;
8507  int nbinvars;
8508  char name[SCIP_MAXSTRLEN];
8509  int capacity;
8510  int b;
8511 
8512  assert(nstarted > nfinished);
8513 
8514  consdata = SCIPconsGetData(cons);
8515  assert(consdata != NULL);
8516  assert(consdata->nvars > 0);
8517 
8518  capacity = consdata->capacity;
8519  assert(capacity > 0);
8520 
8521  nbinvars = 0;
8522  SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8523 
8524  /* construct row name */
8525  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8526 
8527  if( cutsasconss )
8528  {
8529  SCIP_CONS* lincons;
8530 
8531  /* create knapsack constraint for the given time point */
8532  SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8533  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) );
8534 
8535  for( b = 0; b < nbinvars; ++b )
8536  {
8537  SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8538  }
8539 
8540  /* add and release the new constraint */
8541  SCIP_CALL( SCIPaddCons(scip, lincons) );
8542  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8543  }
8544  else
8545  {
8546  SCIP_ROW* row;
8547 
8548  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8549  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8550 
8551  for( b = 0; b < nbinvars; ++b )
8552  {
8553  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8554  }
8555 
8556  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8557  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8558 
8559  if( consdata->demandrowssize == 0 )
8560  {
8561  consdata->demandrowssize = 10;
8562  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8563  }
8564  if( consdata->ndemandrows == consdata->demandrowssize )
8565  {
8566  consdata->demandrowssize *= 2;
8567  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8568  }
8569 
8570  consdata->demandrows[consdata->ndemandrows] = row;
8571  consdata->ndemandrows++;
8572  }
8573 
8574  SCIPfreeBufferArrayNull(scip, &binvars);
8575  SCIPfreeBufferArrayNull(scip, &coefs);
8576 
8577  return SCIP_OKAY;
8578 }
8579 
8580 /** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8581  * row
8582  */
8583 static
8585  SCIP* scip, /**< SCIP data structure */
8586  SCIP_CONS* cons, /**< constraint to be checked */
8587  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8588  )
8589 {
8590  SCIP_CONSDATA* consdata;
8591 
8592  int* starttimes; /* stores when each job is starting */
8593  int* endtimes; /* stores when each job ends */
8594  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8595  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8596 
8597  int nvars; /* number of activities for this constraint */
8598  int freecapacity; /* remaining capacity */
8599  int curtime; /* point in time which we are just checking */
8600  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8601 
8602  int hmin;
8603  int hmax;
8604 
8605  int j;
8606 
8607  assert(scip != NULL);
8608  assert(cons != NULL);
8609 
8610  consdata = SCIPconsGetData(cons);
8611  assert(consdata != NULL);
8612 
8613  nvars = consdata->nvars;
8614 
8615  /* if no activities are associated with this cumulative then this constraint is redundant */
8616  if( nvars == 0 )
8617  return SCIP_OKAY;
8618 
8619  assert(consdata->vars != NULL);
8620 
8621  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8622  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8623  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8624  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8625 
8626  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8627  SCIPconsGetName(cons), nvars);
8628 
8629  /* create event point arrays */
8630  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8631  starttimes, endtimes, startindices, endindices, FALSE);
8632 
8633  endindex = 0;
8634  freecapacity = consdata->capacity;
8635  hmin = consdata->hmin;
8636  hmax = consdata->hmax;
8637 
8638  /* check each startpoint of a job whether the capacity is kept or not */
8639  for( j = 0; j < nvars; ++j )
8640  {
8641  curtime = starttimes[j];
8642  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8643 
8644  if( curtime >= hmax )
8645  break;
8646 
8647  /* remove the capacity requirments for all job which start at the curtime */
8648  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8649 
8650  /* add the capacity requirments for all job which end at the curtime */
8651  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8652 
8653  assert(freecapacity <= consdata->capacity);
8654  assert(endindex <= nvars);
8655 
8656  /* endindex - points to the next job which will finish */
8657  /* j - points to the last job that has been released */
8658 
8659  /* if free capacity is smaller than zero, then add rows to the LP */
8660  if( freecapacity < 0 && curtime >= hmin )
8661  {
8662  int nextstarttime;
8663  int t;
8664 
8665  /* step forward until next job is released and see whether capacity constraint is met or not */
8666  if( j < nvars-1 )
8667  nextstarttime = starttimes[j+1];
8668  else
8669  nextstarttime = endtimes[nvars-1];
8670 
8671  nextstarttime = MIN(nextstarttime, hmax);
8672 
8673  /* create capacity restriction row for current event point */
8674  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8675 
8676  /* create for all points in time between the current event point and next start event point a row if the free
8677  * capacity is still smaller than zero */
8678  for( t = curtime+1 ; t < nextstarttime; ++t )
8679  {
8680  /* add the capacity requirments for all job which end at the curtime */
8681  addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8682 
8683  if( freecapacity < 0 )
8684  {
8685  /* add constraint */
8686  SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8687 
8688  /* create capacity restriction row */
8689  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8690  }
8691  else
8692  break;
8693  }
8694  }
8695  } /*lint --e{850}*/
8696 
8697  /* free all buffer arrays */
8698  SCIPfreeBufferArray(scip, &endindices);
8699  SCIPfreeBufferArray(scip, &startindices);
8700  SCIPfreeBufferArray(scip, &endtimes);
8701  SCIPfreeBufferArray(scip, &starttimes);
8702 
8703  return SCIP_OKAY;
8704 }
8705 
8706 /** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8707  * capacity is larger than the capacity of the cumulative constraint
8708  * - for each necessary point in time:
8709  *
8710  * sum_j sum_t demand_j * x_{j,t} <= capacity
8711  *
8712  * where x(j,t) is the binary variables of job j at time t
8713  */
8714 static
8716  SCIP* scip, /**< SCIP data structure */
8717  SCIP_CONS* cons, /**< cumulative constraint */
8718  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8719  )
8720 {
8721  SCIP_CONSDATA* consdata;
8722 
8723  consdata = SCIPconsGetData(cons);
8724  assert(consdata != NULL);
8725  assert(consdata->demandrows == NULL);
8726  assert(consdata->ndemandrows == 0);
8727 
8728  /* collect the linking constraints */
8729  if( consdata->linkingconss == NULL )
8730  {
8731  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8732  }
8733 
8734  SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8735 
8736  /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8737  if( cutsasconss )
8738  {
8739  if( SCIPconsIsInitial(cons) )
8740  {
8741  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
8742  }
8743  if( SCIPconsIsSeparated(cons) )
8744  {
8745  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
8746  }
8747  if( SCIPconsIsEnforced(cons) )
8748  {
8749  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
8750  }
8751  }
8752 
8753  return SCIP_OKAY;
8754 }
8755 
8756 /** adds linear relaxation of cumulative constraint to the LP */
8757 static
8759  SCIP* scip, /**< SCIP data structure */
8760  SCIP_CONS* cons, /**< cumulative constraint */
8761  SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
8762  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
8763  )
8764 {
8765  SCIP_CONSDATA* consdata;
8766  int r;
8767 
8768  consdata = SCIPconsGetData(cons);
8769  assert(consdata != NULL);
8770 
8771  if( consdata->demandrows == NULL )
8772  {
8773  assert(consdata->ndemandrows == 0);
8774 
8775  SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8776 
8777  return SCIP_OKAY;
8778  }
8779 
8780  for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8781  {
8782  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8783  {
8784  assert(consdata->demandrows[r] != NULL);
8785  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
8786  }
8787  }
8788 
8789  return SCIP_OKAY;
8790 }
8791 
8792 /** checks constraint for violation, and adds it as a cut if possible */
8793 static
8795  SCIP* scip, /**< SCIP data structure */
8796  SCIP_CONS* cons, /**< cumulative constraint to be separated */
8797  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8798  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8799  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8800  )
8801 { /*lint --e{715}*/
8802  SCIP_CONSDATA* consdata;
8803  int ncuts;
8804  int r;
8805 
8806  assert(scip != NULL);
8807  assert(cons != NULL);
8808  assert(separated != NULL);
8809  assert(cutoff != NULL);
8810 
8811  *separated = FALSE;
8812  *cutoff = FALSE;
8813 
8814  consdata = SCIPconsGetData(cons);
8815  assert(consdata != NULL);
8816 
8817  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8818 
8819  if( consdata->demandrows == NULL )
8820  {
8821  assert(consdata->ndemandrows == 0);
8822 
8823  SCIP_CALL( createRelaxation(scip, cons, FALSE) );
8824 
8825  return SCIP_OKAY;
8826  }
8827 
8828  ncuts = 0;
8829 
8830  /* check each row that is not contained in LP */
8831  for( r = 0; r < consdata->ndemandrows; ++r )
8832  {
8833  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8834  {
8835  SCIP_Real feasibility;
8836 
8837  if( sol != NULL )
8838  feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8839  else
8840  feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8841 
8842  if( SCIPisFeasNegative(scip, feasibility) )
8843  {
8844  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
8845  if ( *cutoff )
8846  {
8847  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8848  return SCIP_OKAY;
8849  }
8850  *separated = TRUE;
8851  ncuts++;
8852  }
8853  }
8854  }
8855 
8856  if( ncuts > 0 )
8857  {
8858  SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8859 
8860  /* if successful, reset age of constraint */
8861  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8862  (*separated) = TRUE;
8863  }
8864 
8865  return SCIP_OKAY;
8866 }
8867 
8868 /** checks constraint for violation, and adds it as a cut if possible */
8869 static
8871  SCIP* scip, /**< SCIP data structure */
8872  SCIP_CONS* cons, /**< logic or constraint to be separated */
8873  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8874  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8875  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8876  )
8877 {
8878  SCIP_CONSDATA* consdata;
8879  SCIP_ROW* row;
8880  SCIP_Real minfeasibility;
8881  int r;
8882 
8883  assert(scip != NULL);
8884  assert(cons != NULL);
8885  assert(separated != NULL);
8886  assert(cutoff != NULL);
8887 
8888  *separated = FALSE;
8889  *cutoff = FALSE;
8890 
8891  consdata = SCIPconsGetData(cons);
8892  assert(consdata != NULL);
8893 
8894  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8895 
8896  /* collect the linking constraints */
8897  if( consdata->linkingconss == NULL )
8898  {
8899  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8900  }
8901 
8902  if( !consdata->covercuts )
8903  {
8904  SCIP_CALL( createCoverCuts(scip, cons) );
8905  }
8906 
8907  row = NULL;
8908  minfeasibility = SCIPinfinity(scip);
8909 
8910  /* check each row of small covers that is not contained in LP */
8911  for( r = 0; r < consdata->nscoverrows; ++r )
8912  {
8913  if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8914  {
8915  SCIP_Real feasibility;
8916 
8917  assert(consdata->scoverrows[r] != NULL);
8918  if( sol != NULL )
8919  feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8920  else
8921  feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8922 
8923  if( minfeasibility > feasibility )
8924  {
8925  minfeasibility = feasibility;
8926  row = consdata->scoverrows[r];
8927  }
8928  }
8929  }
8930 
8931  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8932 
8933  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8934  {
8935  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8936  SCIPconsGetName(cons), minfeasibility);
8937 
8938  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8939  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8940  if ( *cutoff )
8941  return SCIP_OKAY;
8942  (*separated) = TRUE;
8943  }
8944 
8945  minfeasibility = SCIPinfinity(scip);
8946  row = NULL;
8947 
8948  /* check each row of small covers that is not contained in LP */
8949  for( r = 0; r < consdata->nbcoverrows; ++r )
8950  {
8951  if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8952  {
8953  SCIP_Real feasibility;
8954 
8955  assert(consdata->bcoverrows[r] != NULL);
8956  if( sol != NULL )
8957  feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8958  else
8959  feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8960 
8961  if( minfeasibility > feasibility )
8962  {
8963  minfeasibility = feasibility;
8964  row = consdata->bcoverrows[r];
8965  }
8966  }
8967  }
8968 
8969  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8970 
8971  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8972  {
8973  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8974  SCIPconsGetName(cons), minfeasibility);
8975 
8976  assert(row != NULL);
8977  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8978  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8979  if ( *cutoff )
8980  return SCIP_OKAY;
8981  (*separated) = TRUE;
8982  }
8983 
8984  return SCIP_OKAY;
8985 }
8986 
8987 /** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
8988 static
8990  SCIP* scip, /**< SCIP data structure */
8991  SCIP_CONS* cons, /**< constraint to be checked */
8992  int* startindices, /**< permutation with rspect to the start times */
8993  int curtime, /**< current point in time */
8994  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8995  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8996  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
8997  SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
8998  )
8999 {
9000  SCIP_CONSDATA* consdata;
9001  char name[SCIP_MAXSTRLEN];
9002  int lhs; /* left hand side of constraint */
9003 
9004  SCIP_VAR** activevars;
9005  SCIP_ROW* row;
9006 
9007  int v;
9008 
9009  assert(nstarted > nfinished);
9010 
9011  consdata = SCIPconsGetData(cons);
9012  assert(consdata != NULL);
9013  assert(consdata->nvars > 0);
9014 
9015  SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
9016 
9017  SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
9018 
9019  if( lower )
9020  {
9021  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
9022 
9023  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, (SCIP_Real) lhs, SCIPinfinity(scip),
9024  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9025  }
9026  else
9027  {
9028  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
9029  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) lhs,
9030  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9031  }
9032 
9033  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
9034 
9035  for( v = 0; v < nstarted - nfinished; ++v )
9036  {
9037  SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
9038  }
9039 
9040  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
9041  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
9042 
9043  SCIP_CALL( SCIPaddRow(scip, row, TRUE, cutoff) );
9044 
9045  SCIP_CALL( SCIPreleaseRow(scip, &row) );
9046 
9047  /* free buffers */
9048  SCIPfreeBufferArrayNull(scip, &activevars);
9049 
9050  return SCIP_OKAY;
9051 }
9052 
9053 /** checks constraint for violation, and adds it as a cut if possible */
9054 static
9056  SCIP* scip, /**< SCIP data structure */
9057  SCIP_CONS* cons, /**< cumulative constraint to be separated */
9058  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
9059  SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
9060  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
9061  SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9062  )
9063 {
9064  SCIP_CONSDATA* consdata;
9065 
9066  int* starttimes; /* stores when each job is starting */
9067  int* endtimes; /* stores when each job ends */
9068  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
9069  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
9070 
9071  int nvars; /* number of activities for this constraint */
9072  int freecapacity; /* remaining capacity */
9073  int curtime; /* point in time which we are just checking */
9074  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
9075 
9076  int hmin;
9077  int hmax;
9078  int j;
9079 
9080  assert(scip != NULL);
9081  assert(cons != NULL);
9082 
9083  consdata = SCIPconsGetData(cons);
9084  assert(consdata != NULL);
9085 
9086  nvars = consdata->nvars;
9087 
9088  /* if no activities are associated with this cumulative then this constraint is redundant */
9089  if( nvars <= 1 )
9090  return SCIP_OKAY;
9091 
9092  assert(consdata->vars != NULL);
9093 
9094  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
9095  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
9096  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9097  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9098 
9099  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9100  SCIPconsGetName(cons), nvars);
9101 
9102  /* create event point arrays */
9103  createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9104 
9105  /* now nvars might be smaller than before! */
9106 
9107  endindex = 0;
9108  freecapacity = consdata->capacity;
9109  hmin = consdata->hmin;
9110  hmax = consdata->hmax;
9111 
9112  /* check each startpoint of a job whether the capacity is kept or not */
9113  for( j = 0; j < nvars && !(*cutoff); ++j )
9114  {
9115  curtime = starttimes[j];
9116 
9117  if( curtime >= hmax )
9118  break;
9119 
9120  /* remove the capacity requirements for all job which start at the curtime */
9121  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9122 
9123  /* add the capacity requirments for all job which end at the curtime */
9124  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9125 
9126  assert(freecapacity <= consdata->capacity);
9127  assert(endindex <= nvars);
9128 
9129  /* endindex - points to the next job which will finish */
9130  /* j - points to the last job that has been released */
9131 
9132  /* if free capacity is smaller than zero, then add rows to the LP */
9133  if( freecapacity < 0 && curtime >= hmin)
9134  {
9135  /* create capacity restriction row for current event point */
9136  SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower, cutoff) );
9137  *separated = TRUE;
9138  }
9139  } /*lint --e{850}*/
9140 
9141  /* free all buffer arrays */
9142  SCIPfreeBufferArray(scip, &endindices);
9143  SCIPfreeBufferArray(scip, &startindices);
9144  SCIPfreeBufferArray(scip, &endtimes);
9145  SCIPfreeBufferArray(scip, &starttimes);
9146 
9147  return SCIP_OKAY;
9148 }
9149 
9150 /**@} */
9151 
9152 
9153 /**@name Presolving
9154  *
9155  * @{
9156  */
9157 
9158 #ifndef NDEBUG
9159 /** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9160  * correct
9161  */
9162 static
9164  SCIP* scip, /**< SCIP data structure */
9165  SCIP_CONS* cons /**< constraint to be checked */
9166  )
9167 {
9168  SCIP_CONSDATA* consdata;
9169  int capacity;
9170  int nvars;
9171  int j;
9172 
9173  assert(scip != NULL);
9174  assert(cons != NULL);
9175 
9176  consdata = SCIPconsGetData(cons);
9177  assert(consdata != NULL);
9178 
9179  nvars = consdata->nvars;
9180 
9181  /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9182  if( nvars <= 1 )
9183  return TRUE;
9184 
9185  assert(consdata->vars != NULL);
9186  capacity = consdata->capacity;
9187 
9188  /* check each activity: if demand is larger than capacity the problem is infeasible */
9189  for ( j = 0; j < nvars; ++j )
9190  {
9191  if( consdata->demands[j] > capacity )
9192  return FALSE;
9193  }
9194 
9195  return TRUE;
9196 }
9197 #endif
9198 
9199 /** delete constraint if it consists of at most one job
9200  *
9201  * @todo this method needs to be adjusted w.r.t. effective horizon
9202  */
9203 static
9205  SCIP* scip, /**< SCIP data structure */
9206  SCIP_CONS* cons, /**< constraint to propagate */
9207  int* ndelconss, /**< pointer to store the number of deleted constraints */
9208  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9209  )
9210 {
9211  SCIP_CONSDATA* consdata;
9212 
9213  assert(scip != NULL);
9214  assert(cons != NULL);
9215 
9216  consdata = SCIPconsGetData(cons);
9217  assert(consdata != NULL);
9218 
9219  if( consdata->nvars == 0 )
9220  {
9221  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9222 
9223  SCIP_CALL( SCIPdelCons(scip, cons) );
9224  (*ndelconss)++;
9225  }
9226  else if( consdata->nvars == 1 )
9227  {
9228  if( consdata->demands[0] > consdata->capacity )
9229  (*cutoff) = TRUE;
9230  else
9231  {
9232  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9233 
9234  SCIP_CALL( SCIPdelCons(scip, cons) );
9235  (*ndelconss)++;
9236  }
9237  }
9238 
9239  return SCIP_OKAY;
9240 }
9241 
9242 /** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9243  * this is done in the SCIP_DECL_CONSINITPRE() callback
9244  */
9245 static
9247  SCIP* scip, /**< SCIP data structure */
9248  SCIP_CONS* cons /**< constraint to propagate */
9249  )
9250 {
9251  SCIP_CONSDATA* consdata;
9252  SCIP_VAR* var;
9253  int demand;
9254  int duration;
9255  int hmin;
9256  int hmax;
9257  int est;
9258  int lct;
9259  int j;
9260 
9261  assert(scip != NULL);
9262  assert(cons != NULL);
9263 
9264  consdata = SCIPconsGetData(cons);
9265  assert(consdata != NULL);
9266 
9267  hmin = consdata->hmin;
9268  hmax = consdata->hmax;
9269 
9270  SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9271  SCIPconsGetName(cons), hmin, hmax);
9272 
9273  for( j = consdata->nvars-1; j >= 0; --j )
9274  {
9275  var = consdata->vars[j];
9276  demand = consdata->demands[j];
9277  duration = consdata->durations[j];
9278 
9279  /* earliest completion time (ect) and latest start time (lst) */
9280  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9281  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9282 
9283  if( demand == 0 || duration == 0 )
9284  {
9285  /* jobs with zero demand or zero duration can be removed */
9286  SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
9287  SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9288 
9289  /* remove variable form constraint */
9290  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9291  }
9292  else if( est >= hmax || lct <= hmin )
9293  {
9294  SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
9295  SCIPvarGetName(var), est, lct - duration, duration);
9296 
9297  /* delete variable at the given position */
9298  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9299 
9300  /* for the statistic we count the number of jobs which are irrelevant */
9301  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9302  }
9303  }
9304 
9305  return SCIP_OKAY;
9306 }
9307 
9308 /** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9309 static
9311  SCIP* scip, /**< SCIP data structure */
9312  SCIP_CONSDATA* consdata, /**< constraint data */
9313  int pos, /**< position of job in the consdata */
9314  int* nchgbds, /**< pointer to store the number of changed bounds */
9315  int* naddconss, /**< pointer to store the number of added constraints */
9316  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9317  )
9318 {
9319  SCIP_VAR* var;
9320  SCIP_Bool tightened;
9321  int duration;
9322  int ect;
9323  int lst;
9324 
9325  assert(scip != NULL);
9326 
9327  /* zero energy jobs should be removed already */
9328  assert(consdata->durations[pos] > 0);
9329  assert(consdata->demands[pos] > 0);
9330 
9331  var = consdata->vars[pos];
9332  assert(var != NULL);
9333  duration = consdata->durations[pos];
9334 
9335  /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9336  SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9337  SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9338 
9339  /* earliest completion time (ect) and latest start time (lst) */
9340  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9341  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9342 
9343  /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9344  if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9345  return SCIP_OKAY;
9346 
9347  if( ect > consdata->hmin && lst < consdata->hmax )
9348  {
9349  /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9350  *cutoff = TRUE;
9351  }
9352  else if( lst < consdata->hmax )
9353  {
9354  /* move the latest start time of this job in such a way that it finishes before or at hmin */
9355  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9356  assert(tightened);
9357  assert(!(*cutoff));
9358  (*nchgbds)++;
9359  }
9360  else if( ect > consdata->hmin )
9361  {
9362  /* move the earliest start time of this job in such a way that it starts after or at hmax */
9363  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9364  assert(tightened);
9365  assert(!(*cutoff));
9366  (*nchgbds)++;
9367  }
9368  else
9369  {
9370  /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9371  * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9372  *
9373  * (var <= hmin - duration) /\ (var >= hmax)
9374  */
9375  SCIP_CONS* cons;
9376 
9377  SCIP_VAR* vartuple[2];
9378  SCIP_BOUNDTYPE boundtypetuple[2];
9379  SCIP_Real boundtuple[2];
9380 
9381  char name[SCIP_MAXSTRLEN];
9382  int leftbound;
9383  int rightbound;
9384 
9385  leftbound = consdata->hmin - duration;
9386  rightbound = consdata->hmax;
9387 
9388  /* allocate temporary memory for arrays */
9389  vartuple[0] = var;
9390  vartuple[1] = var;
9391  boundtuple[0] = (SCIP_Real)leftbound;
9392  boundtuple[1] = (SCIP_Real)rightbound;
9393  boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9394  boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9395 
9396  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9397  SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9398 
9399  /* create and add bounddisjunction constraint */
9400  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9401  TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9402 
9403  SCIPdebugPrintCons(scip, cons, NULL);
9404 
9405  /* add and release the new constraint */
9406  SCIP_CALL( SCIPaddCons(scip, cons) );
9407  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9408  (*naddconss)++;
9409  }
9410 
9411  return SCIP_OKAY;
9412 }
9413 
9414 /** try to removed over sizeed jobs (the demand is larger than the capacity) */
9415 static
9417  SCIP* scip, /**< SCIP data structure */
9418  SCIP_CONS* cons, /**< constraint */
9419  int* nchgbds, /**< pointer to store the number of changed bounds */
9420  int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9421  int* naddconss, /**< pointer to store the number of added constraints */
9422  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9423  )
9424 {
9425  SCIP_CONSDATA* consdata;
9426  int capacity;
9427  int j;
9428 
9429  consdata = SCIPconsGetData(cons);
9430  assert(consdata != NULL);
9431 
9432  /* if a cutoff was already detected just return */
9433  if( *cutoff )
9434  return SCIP_OKAY;
9435 
9436  capacity = consdata->capacity;
9437 
9438  for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9439  {
9440  if( consdata->demands[j] > capacity )
9441  {
9442  SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9443 
9444  /* remove variable form constraint */
9445  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9446  (*nchgcoefs)++;
9447  }
9448  }
9449 
9450  SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9451 
9452  return SCIP_OKAY;
9453 }
9454 
9455 /** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9456 static
9458  SCIP* scip, /**< SCIP data structure */
9459  SCIP_VAR* var, /**< integer variable to fix */
9460  SCIP_Bool uplock, /**< has thet start time variable a up lock */
9461  int* nfixedvars /**< pointer to store the number fixed variables */
9462  )
9463 {
9464  SCIP_Bool infeasible;
9465  SCIP_Bool tightened;
9466  SCIP_Bool roundable;
9467 
9468  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9469  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9470  */
9471  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9472  return SCIP_OKAY;
9473 
9474  /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9475  * handler is the only one locking that variable up
9476  */
9477  assert(uplock == TRUE || uplock == FALSE);
9478  assert((int)TRUE == 1); /*lint !e506*/
9479  assert((int)FALSE == 0); /*lint !e506*/
9480 
9481  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)(uplock) )
9482  return SCIP_OKAY;
9483 
9484  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9485 
9486  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9487  * (the transformed problem is always a minimization problem)
9488  */
9489  if( !roundable )
9490  return SCIP_OKAY;
9491 
9492  SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9494 
9495  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9496  assert(!infeasible);
9497 
9498  if( tightened )
9499  {
9500  SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9501  (*nfixedvars)++;
9502  }
9503 
9504  return SCIP_OKAY;
9505 }
9506 
9507 /** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9508 static
9510  SCIP* scip, /**< SCIP data structure */
9511  SCIP_VAR* var, /**< integer variable to fix */
9512  SCIP_Bool downlock, /**< has the variable a down lock */
9513  int* nfixedvars /**< pointer to store the number fixed variables */
9514  )
9515 {
9516  SCIP_Bool infeasible;
9517  SCIP_Bool tightened;
9518  SCIP_Bool roundable;
9519 
9520  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9521  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9522  */
9523  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9524  return SCIP_OKAY;
9525 
9526  /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9527  * handler is the only one locking that variable down
9528  */
9529  assert(downlock == TRUE || downlock == FALSE);
9530  assert((int)TRUE == 1); /*lint !e506*/
9531  assert((int)FALSE == 0); /*lint !e506*/
9532 
9533  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)(downlock) )
9534  return SCIP_OKAY;
9535 
9536  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9537 
9538  /* is it possible, to round variable down w.r.t. objective function? */
9539  if( !roundable )
9540  return SCIP_OKAY;
9541 
9542  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9543  assert(!infeasible);
9544 
9545  if( tightened )
9546  {
9547  SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9548  (*nfixedvars)++;
9549  }
9550 
9551  return SCIP_OKAY;
9552 }
9553 
9554 /** normalize cumulative condition */
9555 static
9557  SCIP* scip, /**< SCIP data structure */
9558  int nvars, /**< number of start time variables (activities) */
9559  int* demands, /**< array of demands */
9560  int* capacity, /**< pointer to store the changed cumulative capacity */
9561  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9562  int* nchgsides /**< pointer to count number of side changes */
9563  )
9564 { /*lint --e{715}*/
9565  SCIP_Longint gcd;
9566  int mindemand1;
9567  int mindemand2;
9568  int v;
9569 
9570  if( *capacity == 1 || nvars <= 1 )
9571  return;
9572 
9573  assert(demands[nvars-1] <= *capacity);
9574  assert(demands[nvars-2] <= *capacity);
9575 
9576  gcd = (SCIP_Longint)demands[nvars-1];
9577  mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9578  mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9579 
9580  for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9581  {
9582  assert(mindemand1 <= mindemand2);
9583  assert(demands[v] <= *capacity);
9584 
9585  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9586 
9587  if( mindemand1 > demands[v] )
9588  {
9589  mindemand2 = mindemand1;
9590  mindemand1 = demands[v];
9591  }
9592  else if( mindemand2 > demands[v] )
9593  mindemand2 = demands[v];
9594  }
9595 
9596  if( mindemand1 + mindemand2 > *capacity )
9597  {
9598  SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9599 
9600  for( v = 0; v < nvars; ++v )
9601  demands[v] = 1;
9602 
9603  (*capacity) = 1;
9604 
9605  (*nchgcoefs) += nvars;
9606  (*nchgsides)++;
9607  }
9608  else if( gcd >= 2 )
9609  {
9610  SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9611 
9612  for( v = 0; v < nvars; ++v )
9613  demands[v] /= (int) gcd;
9614 
9615  (*capacity) /= (int) gcd;
9616 
9617  (*nchgcoefs) += nvars;
9618  (*nchgsides)++;
9619  }
9620 }
9621 
9622 /** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9623  * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9624  * capacity since in that case none of the jobs can run in parallel
9625  */
9626 static
9627 void normalizeDemands(
9628  SCIP* scip, /**< SCIP data structure */
9629  SCIP_CONS* cons, /**< cumulative constraint */
9630  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9631  int* nchgsides /**< pointer to count number of side changes */
9632  )
9633 {
9634  SCIP_CONSDATA* consdata;
9635  int capacity;
9636 
9637  assert(nchgcoefs != NULL);
9638  assert(nchgsides != NULL);
9639  assert(!SCIPconsIsModifiable(cons));
9640 
9641  consdata = SCIPconsGetData(cons);
9642  assert(consdata != NULL);
9643 
9644  if( consdata->normalized )
9645  return;
9646 
9647  capacity = consdata->capacity;
9648 
9649  /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9650 
9651  normalizeCumulativeCondition(scip, consdata->nvars, consdata->demands, &consdata->capacity, nchgcoefs, nchgsides);
9652 
9653  consdata->normalized = TRUE;
9654 
9655  if( capacity > consdata->capacity )
9656  consdata->varbounds = FALSE;
9657 }
9658 
9659 /** computes for the given cumulative condition the effective horizon */
9660 static
9662  SCIP* scip, /**< SCIP data structure */
9663  int nvars, /**< number of variables (jobs) */
9664  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9665  int* durations, /**< array containing corresponding durations */
9666  int* demands, /**< array containing corresponding demands */
9667  int capacity, /**< available cumulative capacity */
9668  int* hmin, /**< pointer to store the left bound of the effective horizon */
9669  int* hmax, /**< pointer to store the right bound of the effective horizon */
9670  int* split /**< point were the cumulative condition can be split */
9671  )
9672 {
9673  SCIP_PROFILE* profile;
9674 
9675  /* create empty resource profile with infinity resource capacity */
9676  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9677 
9678  /* create worst case resource profile */
9679  SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
9680 
9681  /* print resource profile in if SCIP_DEBUG is defined */
9682  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
9683 
9684  /* computes the first time point where the resource capacity can be violated */
9685  (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9686 
9687  /* computes the first time point where the resource capacity is satisfied for sure */
9688  (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9689 
9690  (*split) = (*hmax);
9691 
9692  if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9693  {
9694  int* timepoints;
9695  int* loads;
9696  int ntimepoints;
9697  int t;
9698 
9699  /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9700  * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9701  * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9702  * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9703  * explain the certain "old" bound changes
9704  */
9705 
9706  /* search for time points */
9707  ntimepoints = SCIPprofileGetNTimepoints(profile);
9708  timepoints = SCIPprofileGetTimepoints(profile);
9709  loads = SCIPprofileGetLoads(profile);
9710 
9711  /* 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 */
9712  for( t = 0; t < ntimepoints; ++t )
9713  {
9714  /* ignore all time points before the effective horizon */
9715  if( timepoints[t] <= *hmin )
9716  continue;
9717 
9718  /* ignore all time points after the effective horizon */
9719  if( timepoints[t] >= *hmax )
9720  break;
9721 
9722  /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9723  * can split the cumulative constraint into two cumulative constraints
9724  */
9725  if( loads[t] <= capacity )
9726  {
9727  (*split) = timepoints[t];
9728  break;
9729  }
9730  }
9731  }
9732 
9733  /* free worst case profile */
9734  SCIPprofileFree(&profile);
9735 
9736  return SCIP_OKAY;
9737 }
9738 
9739 /** creates and adds a cumulative constraint */
9740 static
9742  SCIP* scip, /**< SCIP data structure */
9743  const char* name, /**< name of constraint */
9744  int nvars, /**< number of variables (jobs) */
9745  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9746  int* durations, /**< array containing corresponding durations */
9747  int* demands, /**< array containing corresponding demands */
9748  int capacity, /**< available cumulative capacity */
9749  int hmin, /**< left bound of time axis to be considered (including hmin) */
9750  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9751  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9752  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9753  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9754  * Usually set to TRUE. */
9755  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9756  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9757  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9758  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9759  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9760  * Usually set to TRUE. */
9761  SCIP_Bool local, /**< is constraint only valid locally?
9762  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9763  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9764  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9765  * adds coefficients to this constraint. */
9766  SCIP_Bool dynamic, /**< is constraint subject to aging?
9767  * Usually set to FALSE. Set to TRUE for own cuts which
9768  * are seperated as constraints. */
9769  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9770  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9771  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9772  * if it may be moved to a more global node?
9773  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9774  )
9775 {
9776  SCIP_CONS* cons;
9777 
9778  /* creates cumulative constraint and adds it to problem */
9779  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9780  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9781 
9782  /* adjust the effective time horizon of the new constraint */
9783  SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9784  SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9785 
9786  /* add and release new cumulative constraint */
9787  SCIP_CALL( SCIPaddCons(scip, cons) );
9788  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9789 
9790  return SCIP_OKAY;
9791 }
9792 
9793 /** computes the effective horizon and checks if the constraint can be decompsed */
9794 static
9796  SCIP* scip, /**< SCIP data structure */
9797  SCIP_CONS* cons, /**< cumulative constraint */
9798  int* ndelconss, /**< pointer to store the number of deleted constraints */
9799  int* naddconss, /**< pointer to store the number of added constraints */
9800  int* nchgsides /**< pointer to store the number of changed sides */
9801  )
9802 {
9803  SCIP_CONSDATA* consdata;
9804  int hmin;
9805  int hmax;
9806  int split;
9807 
9808  consdata = SCIPconsGetData(cons);
9809  assert(consdata != NULL);
9810 
9811  if( consdata->nvars <= 1 )
9812  return SCIP_OKAY;
9813 
9814  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9815  consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9816 
9817  /* check if this time point improves the effective horizon */
9818  if( consdata->hmin < hmin )
9819  {
9820  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9821 
9822  consdata->hmin = hmin;
9823  (*nchgsides)++;
9824  }
9825 
9826  /* check if this time point improves the effective horizon */
9827  if( consdata->hmax > hmax )
9828  {
9829  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9830  consdata->hmax = hmax;
9831  (*nchgsides)++;
9832  }
9833 
9834  /* check if the constraint is redundant */
9835  if( consdata->hmax <= consdata->hmin )
9836  {
9837  SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9838  SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9839 
9840  SCIP_CALL( SCIPdelCons(scip, cons) );
9841  (*ndelconss)++;
9842  }
9843  else if( consdata->hmin < split && split < consdata->hmax )
9844  {
9845  char name[SCIP_MAXSTRLEN];
9846  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9847 
9848  SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9849  SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9850 
9851  assert(split < consdata->hmax);
9852 
9853  /* creates cumulative constraint and adds it to problem */
9854  SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9855  consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9858 
9859  /* adjust the effective time horizon of the constraint */
9860  consdata->hmax = split;
9861 
9862  assert(consdata->hmin < consdata->hmax);
9863 
9864  /* for the statistic we count the number of time we decompose a cumulative constraint */
9866  (*naddconss)++;
9867  }
9868 
9869  return SCIP_OKAY;
9870 }
9871 
9872 
9873 /** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9874  *
9875  * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9876  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9877  *
9878  * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9879  * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9880  * down-lock of the corresponding start time variable can be removed.
9881  *
9882  * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9883  * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9884  * negative, than the job can be dual fixed to its earlier start time (est).
9885  *
9886  * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9887  * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9888  * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9889  *
9890  * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9891  * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9892  * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9893  * form variable domain is dual feasible.
9894  *
9895  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9896  * the cumulative condition; The deletion has to be done later.
9897  */
9898 static
9900  SCIP* scip, /**< SCIP data structure */
9901  int nvars, /**< number of start time variables (activities) */
9902  SCIP_VAR** vars, /**< array of start time variables */
9903  int* durations, /**< array of durations */
9904  int hmin, /**< left bound of time axis to be considered (including hmin) */
9905  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9906  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9907  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9908  SCIP_CONS* cons, /**< underlying constraint, or NULL */
9909  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9910  int* nfixedvars, /**< pointer to store the number of fixed variables */
9911  int* nchgsides, /**< pointer to store the number of changed sides */
9912  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9913  )
9914 {
9915  SCIP_Real* downimpllbs;
9916  SCIP_Real* downimplubs;
9917  SCIP_Real* downproplbs;
9918  SCIP_Real* downpropubs;
9919  SCIP_Real* upimpllbs;
9920  SCIP_Real* upimplubs;
9921  SCIP_Real* upproplbs;
9922  SCIP_Real* uppropubs;
9923 
9924  int firstminect;
9925  int secondminect;
9926  int v;
9927 
9928  /* get temporary memory for storing probing results needed for step (4) and (5) */
9929  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9930  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9931  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9932  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9933  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9934  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9935  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9936  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9937 
9938  assert(scip != NULL);
9939  assert(nvars > 1);
9940  assert(cons != NULL);
9941 
9942  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9943 
9944  firstminect = INT_MAX;
9945  secondminect = INT_MAX;
9946 
9947  /* compute the two smallest earlier completion times; which are needed for step (5) */
9948  for( v = 0; v < nvars; ++v )
9949  {
9950  int ect;
9951 
9952  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9953 
9954  if( ect < firstminect )
9955  {
9956  secondminect = firstminect;
9957  firstminect = ect;
9958  }
9959  else if( ect < secondminect )
9960  secondminect = ect;
9961  }
9962 
9963  /* loop over all jobs and check if one of the 5 reductions can be applied */
9964  for( v = 0; v < nvars; ++v )
9965  {
9966  SCIP_VAR* var;
9967  int duration;
9968 
9969  int alternativelb;
9970  int minect;
9971  int est;
9972  int ect;
9973  int lst;
9974  int lct;
9975 
9976  var = vars[v];
9977  assert(var != NULL);
9978 
9979  duration = durations[v];
9980  assert(duration > 0);
9981 
9982  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
9983  * time (lct)
9984  */
9985  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9986  ect = est + duration;
9987  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9988  lct = lst + duration;
9989 
9990  /* compute the earliest completion time of all remaining jobs */
9991  if( ect == firstminect )
9992  minect = secondminect;
9993  else
9994  minect = firstminect;
9995 
9996  /* compute potential alternative lower bound (step (4) and (5)) */
9997  alternativelb = MAX(hmin+1, minect);
9998  alternativelb = MIN(alternativelb, hmax);
9999 
10000  if( lct <= hmin )
10001  {
10002  /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
10003  * cumulative condition
10004  */
10005  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10006  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10007 
10008  /* mark variable to be irrelevant */
10009  irrelevants[v] = TRUE;
10010 
10011  /* for the statistic we count the number of jobs which are irrelevant */
10012  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10013  }
10014  else if( lst <= hmin && SCIPconsIsChecked(cons) )
10015  {
10016  /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
10017  * so the down lock can be omitted
10018  */
10019 
10020  assert(downlocks != NULL);
10021  assert(uplocks != NULL);
10022 
10023  if( !uplocks[v] )
10024  {
10025  /* the variables has no up lock and we can also remove the down lock;
10026  * => lst <= hmin and ect >= hmax
10027  * => remove job and reduce capacity by the demand of that job
10028  *
10029  * We mark the job to be deletable. The removement together with the capacity reducion is done later
10030  */
10031 
10032  SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
10033  SCIPvarGetName(var), ect - duration, lst, duration);
10034 
10035  /* mark variable to be irrelevant */
10036  irrelevants[v] = TRUE;
10037 
10038  /* for the statistic we count the number of jobs which always run during the effective horizon */
10040  }
10041 
10042  if( downlocks[v] )
10043  {
10044  SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
10045  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10046 
10047  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
10048  downlocks[v] = FALSE;
10049  (*nchgsides)++;
10050 
10051  /* for the statistic we count the number of removed locks */
10053  }
10054  }
10055  else if( ect <= hmin )
10056  {
10057  /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
10058  * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
10059  * removed form the cumulative condition after it was fixed to its earliest start time
10060  */
10061 
10062  /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
10063  * bound;
10064  */
10065  if( downlocks != NULL && SCIPconsIsChecked(cons) )
10066  {
10067  /* fix integer start time variable if possible to it lower bound */
10068  SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
10069  }
10070 
10071  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10072  {
10073  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
10074  SCIPvarGetName(var), ect - duration, lst, duration);
10075 
10076  /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
10077  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
10078 
10079  /* mark variable to be irrelevant */
10080  irrelevants[v] = TRUE;
10081 
10082  /* for the statistic we count the number of jobs which are dual fixed */
10084  }
10085  }
10086  else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10087  {
10088  assert(downlocks != NULL);
10089 
10090  /* check step (4) and (5) */
10091 
10092  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10093  * is in favor of rounding the variable down
10094  */
10095  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
10096  {
10097  SCIP_Bool roundable;
10098 
10099  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10100 
10101  if( roundable )
10102  {
10103  if( alternativelb > lst )
10104  {
10105  SCIP_Bool infeasible;
10106  SCIP_Bool fixed;
10107 
10108  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10109  assert(!infeasible);
10110  assert(fixed);
10111 
10112  (*nfixedvars)++;
10113 
10114  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10115  * constraints
10116  */
10118  }
10119  else
10120  {
10121  SCIP_Bool success;
10122 
10123  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10124  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10125  * infeasible we can apply the dual reduction; otherwise we do nothing
10126  */
10127  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10128  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10129  nfixedvars, &success, cutoff) );
10130 
10131  if( success )
10132  {
10134  }
10135  }
10136  }
10137  }
10138  }
10139 
10140  SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10141  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10142  }
10143 
10144  /* free temporary memory */
10145  SCIPfreeBufferArray(scip, &uppropubs);
10146  SCIPfreeBufferArray(scip, &upproplbs);
10147  SCIPfreeBufferArray(scip, &upimplubs);
10148  SCIPfreeBufferArray(scip, &upimpllbs);
10149  SCIPfreeBufferArray(scip, &downpropubs);
10150  SCIPfreeBufferArray(scip, &downproplbs);
10151  SCIPfreeBufferArray(scip, &downimplubs);
10152  SCIPfreeBufferArray(scip, &downimpllbs);
10153 
10154  return SCIP_OKAY;
10155 }
10156 
10157 /** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10158  *
10159  * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10160  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10161  *
10162  * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10163  * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10164  * up-lock of the corresponding start time variable can be removed.
10165  *
10166  * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10167  * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10168  * positive, than the job can be dual fixed to its latest start time (lst).
10169  *
10170  * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10171  * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10172  * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10173  * of the corresponding job).
10174 
10175  * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10176  * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10177  * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10178  * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10179  *
10180  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10181  * the cumulative condition; The deletion has to be done later.
10182  */
10183 static
10185  SCIP* scip, /**< SCIP data structure */
10186  int nvars, /**< number of start time variables (activities) */
10187  SCIP_VAR** vars, /**< array of start time variables */
10188  int* durations, /**< array of durations */
10189  int hmin, /**< left bound of time axis to be considered (including hmin) */
10190  int hmax, /**< right bound of time axis to be considered (not including hmax) */
10191  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10192  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10193  SCIP_CONS* cons, /**< underlying constraint, or NULL */
10194  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10195  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10196  int* nchgsides, /**< pointer to store the number of changed sides */
10197  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10198  )
10199 {
10200  SCIP_Real* downimpllbs;
10201  SCIP_Real* downimplubs;
10202  SCIP_Real* downproplbs;
10203  SCIP_Real* downpropubs;
10204  SCIP_Real* upimpllbs;
10205  SCIP_Real* upimplubs;
10206  SCIP_Real* upproplbs;
10207  SCIP_Real* uppropubs;
10208 
10209  int firstmaxlst;
10210  int secondmaxlst;
10211  int v;
10212 
10213  /* get temporary memory for storing probing results needed for step (4) and (5) */
10214  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10215  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10216  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10217  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10218  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10219  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10220  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10221  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10222 
10223  assert(scip != NULL);
10224  assert(nvars > 1);
10225  assert(cons != NULL);
10226 
10227  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10228 
10229  firstmaxlst = INT_MIN;
10230  secondmaxlst = INT_MIN;
10231 
10232  /* compute the two largest latest start times; which are needed for step (5) */
10233  for( v = 0; v < nvars; ++v )
10234  {
10235  int lst;
10236 
10237  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(vars[v]));
10238 
10239  if( lst > firstmaxlst )
10240  {
10241  secondmaxlst = firstmaxlst;
10242  firstmaxlst = lst;
10243  }
10244  else if( lst > secondmaxlst )
10245  secondmaxlst = lst;
10246  }
10247 
10248  /* loop over all jobs and check if one of the 5 reductions can be applied */
10249  for( v = 0; v < nvars; ++v )
10250  {
10251  SCIP_VAR* var;
10252  int duration;
10253 
10254  int alternativeub;
10255  int maxlst;
10256  int est;
10257  int ect;
10258  int lst;
10259 
10260  var = vars[v];
10261  assert(var != NULL);
10262 
10263  duration = durations[v];
10264  assert(duration > 0);
10265 
10266  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10267  * time (lct)
10268  */
10269  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10270  ect = est + duration;
10271  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10272 
10273  /* compute the latest start time of all remaining jobs */
10274  if( lst == firstmaxlst )
10275  maxlst = secondmaxlst;
10276  else
10277  maxlst = firstmaxlst;
10278 
10279  /* compute potential alternative upper bound (step (4) and (5)) */
10280  alternativeub = MIN(hmax - 1, maxlst) - duration;
10281  alternativeub = MAX(alternativeub, hmin);
10282 
10283  if( est >= hmax )
10284  {
10285  /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10286  * cumulative condition
10287  */
10288  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10289  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10290 
10291  /* mark variable to be irrelevant */
10292  irrelevants[v] = TRUE;
10293 
10294  /* for the statistic we count the number of jobs which are irrelevant */
10295  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10296  }
10297  else if( ect >= hmax && SCIPconsIsChecked(cons) )
10298  {
10299  assert(downlocks != NULL);
10300  assert(uplocks != NULL);
10301 
10302  /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10303  * so the up lock can be omitted
10304  */
10305 
10306  if( !downlocks[v] )
10307  {
10308  /* the variables has no down lock and we can also remove the up lock;
10309  * => lst <= hmin and ect >= hmax
10310  * => remove job and reduce capacity by the demand of that job
10311  */
10312  SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10313  SCIPvarGetName(var), est, lst, duration);
10314 
10315  /* mark variable to be irrelevant */
10316  irrelevants[v] = TRUE;
10317 
10318  /* for the statistic we count the number of jobs which always run during the effective horizon */
10320  }
10321 
10322  if( uplocks[v] )
10323  {
10324  SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10325  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10326 
10327  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10328  uplocks[v] = FALSE;
10329  (*nchgsides)++;
10330 
10331  /* for the statistic we count the number of removed locks */
10333  }
10334  }
10335  else if( lst >= hmax )
10336  {
10337  /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10338  * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10339  * removed form the cumulative condition after it was fixed to its latest start time
10340  */
10341 
10342  /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10343  * bound
10344  */
10345  if( uplocks != NULL && SCIPconsIsChecked(cons) )
10346  {
10347  /* fix integer start time variable if possible to its upper bound */
10348  SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10349  }
10350 
10351  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10352  {
10353  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10354  SCIPvarGetName(var), est, lst, duration);
10355 
10356  /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10357  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10358 
10359  /* mark variable to be irrelevant */
10360  irrelevants[v] = TRUE;
10361 
10362  /* for the statistic we count the number of jobs which are dual fixed */
10364  }
10365  }
10366  else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10367  {
10368  assert(uplocks != NULL);
10369 
10370  /* check step (4) and (5) */
10371 
10372  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10373  * is in favor of rounding the variable down
10374  */
10375  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
10376  {
10377  SCIP_Bool roundable;
10378 
10379  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10380 
10381  if( roundable )
10382  {
10383  if( alternativeub < est )
10384  {
10385  SCIP_Bool infeasible;
10386  SCIP_Bool fixed;
10387 
10388  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10389  assert(!infeasible);
10390  assert(fixed);
10391 
10392  (*nfixedvars)++;
10393 
10394  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10395  * constraints
10396  */
10398  }
10399  else
10400  {
10401  SCIP_Bool success;
10402 
10403  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10404  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10405  * in infeasible we can apply the dual reduction; otherwise we do nothing
10406  */
10407  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10408  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10409  nfixedvars, &success, cutoff) );
10410 
10411  if( success )
10412  {
10414  }
10415  }
10416  }
10417  }
10418  }
10419  }
10420 
10421  /* free temporary memory */
10422  SCIPfreeBufferArray(scip, &uppropubs);
10423  SCIPfreeBufferArray(scip, &upproplbs);
10424  SCIPfreeBufferArray(scip, &upimplubs);
10425  SCIPfreeBufferArray(scip, &upimpllbs);
10426  SCIPfreeBufferArray(scip, &downpropubs);
10427  SCIPfreeBufferArray(scip, &downproplbs);
10428  SCIPfreeBufferArray(scip, &downimplubs);
10429  SCIPfreeBufferArray(scip, &downimpllbs);
10430 
10431  return SCIP_OKAY;
10432 }
10433 
10434 /** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10435 static
10437  SCIP* scip, /**< SCIP data structure */
10438  SCIP_CONS* cons, /**< cumulative constraint */
10439  int* nfixedvars, /**< pointer to store the number of fixed variables */
10440  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10441  int* nchgsides, /**< pointer to store the number of changed sides */
10442  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10443  )
10444 {
10445  SCIP_CONSDATA* consdata;
10446  SCIP_Bool* irrelevants;
10447  int nvars;
10448  int v;
10449 
10450  assert(scip != NULL);
10451  assert(cons != NULL);
10452  assert(!(*cutoff));
10453 
10454  consdata = SCIPconsGetData(cons);
10455  assert(consdata != NULL);
10456 
10457  nvars = consdata->nvars;
10458 
10459  if( nvars <= 1 )
10460  return SCIP_OKAY;
10461 
10462  SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10463  BMSclearMemoryArray(irrelevants, nvars);
10464 
10465  /* presolve constraint form the earlier start time point of view */
10466  SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10467  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10468  irrelevants, nfixedvars, nchgsides, cutoff) );
10469 
10470  /* presolve constraint form the latest completion time point of view */
10471  SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10472  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10473  irrelevants, nfixedvars, nchgsides, cutoff) );
10474 
10475  /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10476  * order to ensure a correct behaviour
10477  */
10478  for( v = nvars-1; v >= 0; --v )
10479  {
10480  if( irrelevants[v] )
10481  {
10482  SCIP_VAR* var;
10483  int ect;
10484  int lst;
10485 
10486  var = consdata->vars[v];
10487  assert(var != NULL);
10488 
10489  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10490  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10491 
10492  /* check if the jobs runs completely during the effective horizon */
10493  if( lst <= consdata->hmin && ect >= consdata->hmax )
10494  {
10495  if( consdata->capacity < consdata->demands[v] )
10496  {
10497  *cutoff = TRUE;
10498  break;
10499  }
10500 
10501  consdata->capacity -= consdata->demands[v];
10502  consdata->varbounds = FALSE;
10503  }
10504 
10505  SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10506  (*nchgcoefs)++;
10507  }
10508  }
10509 
10510  SCIPfreeBufferArray(scip, &irrelevants);
10511 
10512  return SCIP_OKAY;
10513 }
10514 
10515 /** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10516 static
10517 void collectDemands(
10518  SCIP* scip, /**< SCIP data structure */
10519  SCIP_CONSDATA* consdata, /**< constraint data */
10520  int* startindices, /**< permutation with rspect to the start times */
10521  int curtime, /**< current point in time */
10522  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10523  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10524  SCIP_Longint** demands, /**< pointer to array storing the demands */
10525  int* ndemands /**< pointer to store the number of different demands */
10526  )
10527 {
10528  int startindex;
10529  int ncountedvars;
10530 
10531  assert(demands != NULL);
10532  assert(ndemands != NULL);
10533 
10534  ncountedvars = 0;
10535  startindex = nstarted - 1;
10536 
10537  *ndemands = 0;
10538 
10539  /* search for the (nstarted - nfinished) jobs which are active at curtime */
10540  while( nstarted - nfinished > ncountedvars )
10541  {
10542  SCIP_VAR* var;
10543  int endtime;
10544  int varidx;
10545 
10546  /* collect job information */
10547  varidx = startindices[startindex];
10548  assert(varidx >= 0 && varidx < consdata->nvars);
10549 
10550  var = consdata->vars[varidx];
10551  assert(var != NULL);
10552 
10553  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10554 
10555  /* check the end time of this job is larger than the curtime; in this case the job is still running */
10556  if( endtime > curtime )
10557  {
10558  if( consdata->demands[varidx] < consdata->capacity )
10559  {
10560  (*demands)[*ndemands] = consdata->demands[varidx];
10561  (*ndemands)++;
10562  }
10563  ncountedvars++;
10564  }
10565 
10566  startindex--;
10567  }
10568 }
10569 
10570 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10571  * constraint
10572  */
10573 static
10575  SCIP* scip, /**< SCIP data structure */
10576  SCIP_CONS* cons, /**< constraint to be checked */
10577  int* startindices, /**< permutation with rspect to the start times */
10578  int curtime, /**< current point in time */
10579  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10580  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10581  int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10582  )
10583 {
10584  SCIP_CONSDATA* consdata;
10585  SCIP_Longint* demands;
10586  SCIP_Real* profits;
10587  int* items;
10588  int ndemands;
10589  SCIP_Bool success;
10590  SCIP_Real solval;
10591  int j;
10592  assert(nstarted > nfinished);
10593 
10594  consdata = SCIPconsGetData(cons);
10595  assert(consdata != NULL);
10596  assert(consdata->nvars > 0);
10597  assert(consdata->capacity > 0);
10598 
10599  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10600  ndemands = 0;
10601 
10602  /* get demand array to initialize knapsack problem */
10603  collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands);
10604 
10605  /* create array for profits */
10606  SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10607  SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10608  for( j = 0; j < ndemands; ++j )
10609  {
10610  profits[j] = (SCIP_Real) demands[j];
10611  items[j] = j;/* this is only a dummy value*/
10612  }
10613 
10614  /* solve knapsack problem and get maximum capacity usage <= capacity */
10615  SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10616  items, NULL, NULL, NULL, NULL, &solval, &success) );
10617 
10618  assert(SCIPisFeasIntegral(scip, solval));
10619 
10620  /* store result */
10621  *bestcapacity = SCIPconvertRealToInt(scip, solval);
10622 
10623  SCIPfreeBufferArray(scip, &items);
10624  SCIPfreeBufferArray(scip, &profits);
10625  SCIPfreeBufferArray(scip, &demands);
10626 
10627  return SCIP_OKAY;
10628 }
10629 
10630 /** try to tighten the capacity
10631  * -- using DP for knapsack, we find the maximum possible capacity usage
10632  * -- neglects hmin and hmax, such that it is also able to check solutions globally
10633  */
10634 static
10636  SCIP* scip, /**< SCIP data structure */
10637  SCIP_CONS* cons, /**< cumulative constraint */
10638  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10639  int* nchgsides /**< pointer to store the number of changed sides */
10640  )
10641 {
10642  SCIP_CONSDATA* consdata;
10643  int* starttimes; /* stores when each job is starting */
10644  int* endtimes; /* stores when each job ends */
10645  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10646  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10647 
10648  int nvars; /* number of activities for this constraint */
10649  int freecapacity; /* remaining capacity */
10650  int curtime; /* point in time which we are just checking */
10651  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10652 
10653  int bestcapacity;
10654 
10655  int j;
10656 
10657  assert(scip != NULL);
10658  assert(cons != NULL);
10659  assert(nchgsides != NULL);
10660 
10661  consdata = SCIPconsGetData(cons);
10662  assert(consdata != NULL);
10663 
10664  nvars = consdata->nvars;
10665 
10666  /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10667  if( nvars <= 1 || consdata->capacity <= 1 )
10668  return SCIP_OKAY;
10669 
10670  assert(consdata->vars != NULL);
10671 
10672  SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10673  SCIPconsGetName(cons), consdata->capacity);
10674 
10675  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10676  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10677  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10678  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10679 
10680  /* create event point arrays */
10681  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10682  starttimes, endtimes, startindices, endindices, FALSE);
10683 
10684  bestcapacity = 1;
10685  endindex = 0;
10686  freecapacity = consdata->capacity;
10687 
10688  /* check each startpoint of a job whether the capacity is kept or not */
10689  for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10690  {
10691  curtime = starttimes[j];
10692  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10693 
10694  /* remove the capacity requirments for all job which start at the curtime */
10695  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10696 
10697  /* add the capacity requirments for all job which end at the curtime */
10698  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10699 
10700  assert(freecapacity <= consdata->capacity);
10701  assert(endindex <= nvars);
10702 
10703  /* endindex - points to the next job which will finish */
10704  /* j - points to the last job that has been released */
10705 
10706  /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10707  if( freecapacity < 0 )
10708  {
10709  int newcapacity;
10710 
10711  newcapacity = 1;
10712 
10713  /* get best possible upper bound on capacity usage */
10714  SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10715 
10716  /* update bestcapacity */
10717  bestcapacity = MAX(bestcapacity, newcapacity);
10718  SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10719  }
10720 
10721  /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10722  if( freecapacity > 0 && freecapacity != consdata->capacity )
10723  {
10724  bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10725  SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10726  }
10727 
10728  /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10729  if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10730  {
10731  /* if demands[startindices[j]] == cap then exactly that job is running */
10732  SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10733  bestcapacity = consdata->capacity;
10734  break;
10735  }
10736  } /*lint --e{850}*/
10737 
10738  /* free all buffer arrays */
10739  SCIPfreeBufferArray(scip, &endindices);
10740  SCIPfreeBufferArray(scip, &startindices);
10741  SCIPfreeBufferArray(scip, &endtimes);
10742  SCIPfreeBufferArray(scip, &starttimes);
10743 
10744  /* check whether capacity can be tightened and whether demands need to be adjusted */
10745  if( bestcapacity < consdata->capacity )
10746  {
10747  SCIPdebug( int oldnchgcoefs = *nchgcoefs; )
10748 
10749  SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10750  SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10751 
10752  for( j = 0; j < nvars; ++j )
10753  {
10754  if( consdata->demands[j] == consdata->capacity )
10755  {
10756  consdata->demands[j] = bestcapacity;
10757  (*nchgcoefs)++;
10758  }
10759  }
10760 
10761  consdata->capacity = bestcapacity;
10762  (*nchgsides)++;
10763 
10764  SCIPdebug( SCIPdebugMsg(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs); )
10765 
10766  consdata->varbounds = FALSE;
10767  }
10768 
10769  return SCIP_OKAY;
10770 }
10771 
10772 /** tries to change coefficients:
10773  * demand_j < cap && all other parallel jobs in conflict
10774  * ==> set demand_j := cap
10775  */
10776 static
10778  SCIP* scip, /**< SCIP data structure */
10779  SCIP_CONS* cons, /**< cumulative constraint */
10780  int* nchgcoefs /**< pointer to count total number of changed coefficients */
10781  )
10782 {
10783  SCIP_CONSDATA* consdata;
10784  int nvars;
10785  int j;
10786  int oldnchgcoefs;
10787  int mindemand;
10788 
10789  assert(scip != NULL);
10790  assert(cons != NULL);
10791  assert(nchgcoefs != NULL);
10792 
10793  /* get constraint data for some parameter testings only! */
10794  consdata = SCIPconsGetData(cons);
10795  assert(consdata != NULL);
10796 
10797  nvars = consdata->nvars;
10798  oldnchgcoefs = *nchgcoefs;
10799 
10800  if( nvars <= 0 )
10801  return SCIP_OKAY;
10802 
10803  /* PRE1:
10804  * check all jobs j whether: r_j + r_min > capacity holds
10805  * if so: adjust r_j to capacity
10806  */
10807  mindemand = consdata->demands[0];
10808  for( j = 0; j < nvars; ++j )
10809  {
10810  mindemand = MIN(mindemand, consdata->demands[j]);
10811  }
10812 
10813  /*check each job */
10814  for( j = 0; j < nvars; ++j )
10815  {
10816  if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10817  {
10818  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10819  consdata->demands[j], consdata->capacity);
10820  consdata->demands[j] = consdata->capacity;
10821  (*nchgcoefs)++;
10822  }
10823  }
10824 
10825  /* PRE2:
10826  * check for each job (with d_j < cap)
10827  * whether it is disjunctive to all others over the time horizon
10828  */
10829  for( j = 0; j < nvars; ++j )
10830  {
10831  SCIP_Bool chgcoef;
10832  int est_j;
10833  int lct_j;
10834  int i;
10835 
10836  assert(consdata->demands[j] <= consdata->capacity);
10837 
10838  if( consdata->demands[j] == consdata->capacity )
10839  continue;
10840 
10841  chgcoef = TRUE;
10842 
10843  est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10844  lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10845 
10846  for( i = 0; i < nvars; ++i )
10847  {
10848  int est_i;
10849  int lct_i;
10850 
10851  if( i == j )
10852  continue;
10853 
10854  est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10855  lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10856 
10857  if( est_i >= lct_j || est_j >= lct_i )
10858  continue;
10859 
10860  if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10861  {
10862  chgcoef = FALSE;
10863  break;
10864  }
10865  }
10866 
10867  if( chgcoef )
10868  {
10869  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10870  consdata->demands[j], consdata->capacity);
10871  consdata->demands[j] = consdata->capacity;
10872  (*nchgcoefs)++;
10873  }
10874  }
10875 
10876  if( (*nchgcoefs) > oldnchgcoefs )
10877  {
10878  SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10879  (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10880  }
10881 
10882  return SCIP_OKAY;
10883 }
10884 
10885 #if 0
10886 /** try to reformulate constraint by replacing certain jobs */
10887 static
10888 SCIP_RETCODE reformulateCons(
10889  SCIP* scip, /**< SCIP data structure */
10890  SCIP_CONS* cons, /**< cumulative constraint */
10891  int* naggrvars /**< pointer to store the number of aggregated variables */
10892  )
10893 {
10894  SCIP_CONSDATA* consdata;
10895  int hmin;
10896  int hmax;
10897  int nvars;
10898  int v;
10899 
10900  consdata = SCIPconsGetData(cons);
10901  assert(cons != NULL);
10902 
10903  nvars = consdata->nvars;
10904  assert(nvars > 1);
10905 
10906  hmin = consdata->hmin;
10907  hmax = consdata->hmax;
10908  assert(hmin < hmax);
10909 
10910  for( v = 0; v < nvars; ++v )
10911  {
10912  SCIP_VAR* var;
10913  int duration;
10914  int est;
10915  int ect;
10916  int lst;
10917  int lct;
10918 
10919  var = consdata->vars[v];
10920  assert(var != NULL);
10921 
10922  duration = consdata->durations[v];
10923 
10924  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10925  ect = est + duration;
10926  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10927  lct = lst + duration;
10928 
10929  /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10930  assert(lst > hmin || ect < hmax);
10931 
10932  if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10933  {
10934  SCIP_VAR* aggrvar;
10935  char name[SCIP_MAXSTRLEN];
10936  SCIP_Bool infeasible;
10937  SCIP_Bool redundant;
10938  SCIP_Bool aggregated;
10939  int shift;
10940 
10941  shift = est - (hmin - lct + MIN(hmin, ect));
10942  assert(shift > 0);
10943  lst = hmin;
10944  duration = hmin - lct;
10945 
10946  SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10947  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10948 
10949  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10950  SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10952  SCIP_CALL( SCIPaddVar(scip, var) );
10953  SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10954 
10955  assert(!infeasible);
10956  assert(!redundant);
10957  assert(aggregated);
10958 
10959  /* replace variable */
10960  consdata->durations[v] = duration;
10961  consdata->vars[v] = aggrvar;
10962 
10963  /* remove and add locks */
10964  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10965  SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10966 
10967  SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10968 
10969  (*naggrvars)++;
10970  }
10971  }
10972 
10973  return SCIP_OKAY;
10974 }
10975 #endif
10976 
10977 /** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10978 static
10980  SCIP* scip, /**< SCIP data structure */
10981  SCIP_CONS* cons, /**< cumulative constraint */
10982  int* naddconss /**< pointer to store the number of added constraints */
10983  )
10984 {
10985  SCIP_CONSDATA* consdata;
10986  SCIP_VAR** vars;
10987  int* durations;
10988  int* demands;
10989  int capacity;
10990  int halfcapacity;
10991  int mindemand;
10992  int nvars;
10993  int v;
10994 
10995  consdata = SCIPconsGetData(cons);
10996  assert(consdata != NULL);
10997 
10998  capacity = consdata->capacity;
10999 
11000  if( capacity == 1 )
11001  return SCIP_OKAY;
11002 
11003  SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
11004  SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
11005  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
11006 
11007  halfcapacity = capacity / 2;
11008  mindemand = consdata->capacity;
11009  nvars = 0;
11010 
11011  /* collect all jobs with demand larger than half of the capacity */
11012  for( v = 0; v < consdata->nvars; ++v )
11013  {
11014  if( consdata->demands[v] > halfcapacity )
11015  {
11016  vars[nvars] = consdata->vars[v];
11017  demands[nvars] = 1;
11018  durations[nvars] = consdata->durations[v];
11019  nvars++;
11020 
11021  mindemand = MIN(mindemand, consdata->demands[v]);
11022  }
11023  }
11024 
11025  if( nvars > 0 )
11026  {
11027  /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
11028  * job is still to large to be scheduled in parallel
11029  */
11030  for( v = 0; v < consdata->nvars; ++v )
11031  {
11032  if( consdata->demands[v] > halfcapacity )
11033  continue;
11034 
11035  if( mindemand + consdata->demands[v] > capacity )
11036  {
11037  demands[nvars] = 1;
11038  durations[nvars] = consdata->durations[v];
11039  vars[nvars] = consdata->vars[v];
11040  nvars++;
11041 
11042  /* @todo create one cumulative constraint and look for another small demand */
11043  break;
11044  }
11045  }
11046 
11047  /* creates cumulative constraint and adds it to problem */
11048  SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
11050  (*naddconss)++;
11051  }
11052 
11053  SCIPfreeBufferArray(scip, &demands);
11054  SCIPfreeBufferArray(scip, &durations);
11055  SCIPfreeBufferArray(scip, &vars);
11056 
11057  return SCIP_OKAY;
11058 }
11059 
11060 /** presolve given constraint */
11061 static
11063  SCIP* scip, /**< SCIP data structure */
11064  SCIP_CONS* cons, /**< cumulative constraint */
11065  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
11066  SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
11067  int* nfixedvars, /**< pointer to store the number of fixed variables */
11068 #if 0
11069  int* naggrvars, /**< pointer to counter which is increased by the number of deduced variable aggregations */
11070 #endif
11071  int* nchgbds, /**< pointer to store the number of changed bounds */
11072  int* ndelconss, /**< pointer to store the number of deleted constraints */
11073  int* naddconss, /**< pointer to store the number of added constraints */
11074  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
11075  int* nchgsides, /**< pointer to store the number of changed sides */
11076  SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
11077  SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
11078  )
11079 {
11080  assert(!SCIPconsIsDeleted(cons));
11081 
11082  /* only perform dual reductions on model constraints */
11083  if( conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) )
11084  {
11085  /* computes the effective horizon and checks if the constraint can be decomposed */
11086  SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11087 
11088  if( SCIPconsIsDeleted(cons) )
11089  return SCIP_OKAY;
11090 
11091  /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11092  * fixings (dual reductions)
11093  */
11094  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11095  {
11096  SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11097 
11098  if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11099  return SCIP_OKAY;
11100  }
11101 
11102  SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11103 
11104  if( *cutoff || SCIPconsIsDeleted(cons) )
11105  return SCIP_OKAY;
11106  }
11107 
11108  /* remove jobs which have a demand larger than the capacity */
11109  SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11110  assert((*cutoff) || checkDemands(scip, cons));
11111 
11112  if( *cutoff )
11113  return SCIP_OKAY;
11114 
11115  if( conshdlrdata->normalize )
11116  {
11117  /* divide demands by their greatest common divisor */
11118  normalizeDemands(scip, cons, nchgcoefs, nchgsides);
11119  }
11120 
11121  /* delete constraint with one job */
11122  SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11123 
11124  if( *cutoff || SCIPconsIsDeleted(cons) )
11125  return SCIP_OKAY;
11126 
11127  if( conshdlrdata->coeftightening )
11128  {
11129  /* try to tighten the capacity */
11130  SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11131 
11132  /* try to tighten the coefficients */
11133  SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11134  }
11135 
11136  assert(checkDemands(scip, cons) || *cutoff);
11137 
11138 #if 0
11139  SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11140 #endif
11141 
11142  return SCIP_OKAY;
11143 }
11144 
11145 /**@name TClique Graph callbacks
11146  *
11147  * @{
11148  */
11149 
11150 /** tclique graph data */
11151 struct TCLIQUE_Graph
11152 {
11153  SCIP_VAR** vars; /**< start time variables each of them is a node */
11154  SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11155  SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11156  SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11157  TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11158  int* ninarcs; /**< number if in arcs for the precedence graph */
11159  int* noutarcs; /**< number if out arcs for the precedence graph */
11160  int* durations; /**< for each node the duration of the corresponding job */
11161  int nnodes; /**< number of nodes */
11162  int size; /**< size of the array */
11163 };
11164 
11165 /** gets number of nodes in the graph */
11166 static
11167 TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11169  assert(tcliquegraph != NULL);
11170 
11171  return tcliquegraph->nnodes;
11172 }
11173 
11174 /** gets weight of nodes in the graph */
11175 static
11176 TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11178  assert(tcliquegraph != NULL);
11179 
11180  return tcliquegraph->weights;
11181 }
11182 
11183 /** returns, whether the edge (node1, node2) is in the graph */
11184 static
11185 TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11187  assert(tcliquegraph != NULL);
11188  assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11189  assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11190 
11191  /* check if an arc exits in the precedence graph */
11192  if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11193  return TRUE;
11194 
11195  /* check if an edge exits in the non-overlapping graph */
11196  if( tcliquegraph->demandmatrix[node1][node2] )
11197  return TRUE;
11198 
11199  return FALSE;
11200 }
11201 
11202 /** selects all nodes from a given set of nodes which are adjacent to a given node
11203  * and returns the number of selected nodes
11204  */
11205 static
11206 TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11208  int nadjnodes;
11209  int i;
11210 
11211  assert(tcliquegraph != NULL);
11212  assert(0 <= node && node < tcliquegraph->nnodes);
11213  assert(nnodes == 0 || nodes != NULL);
11214  assert(adjnodes != NULL);
11215 
11216  nadjnodes = 0;
11217 
11218  for( i = 0; i < nnodes; i++ )
11219  {
11220  /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11221  assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11222  assert(i == 0 || nodes[i-1] < nodes[i]);
11223 
11224  /* check if an edge exists */
11225  if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11226  {
11227  /* current node is adjacent to given node */
11228  adjnodes[nadjnodes] = nodes[i];
11229  nadjnodes++;
11230  }
11231  }
11232 
11233  return nadjnodes;
11234 }
11235 
11236 /** generates cuts using a clique found by algorithm for maximum weight clique
11237  * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11238  */
11239 static
11240 TCLIQUE_NEWSOL(tcliqueNewsolClique)
11241 { /*lint --e{715}*/
11242  SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11243 }
11244 
11245 /** print the tclique graph */
11246 #if 0
11247 static
11248 void tcliquePrint(
11249  SCIP* scip, /**< SCIP data structure */
11250  TCLIQUE_GRAPH* tcliquegraph /**< tclique graph */
11251  )
11252 {
11253  int nnodes;
11254  int i;
11255  int j;
11256 
11257  nnodes = tcliquegraph->nnodes;
11258 
11259  for( i = 0; i < nnodes; ++i )
11260  {
11261  for( j = 0; j < nnodes; ++j )
11262  {
11263  SCIPinfoMessage(scip, NULL, "(%d/%d) ", tcliquegraph->precedencematrix[i][j], tcliquegraph->demandmatrix[i][j]);
11264  }
11265  SCIPinfoMessage(scip, NULL, "\n");
11266  }
11267 }
11268 #endif
11269 
11270 /** @} */
11271 
11272 /** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11273  * job corresponding to variable bound variable (vlbvar)
11274  *
11275  * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11276  */
11277 static
11279  SCIP* scip, /**< SCIP data structure */
11280  SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11281  SCIP_Real vlbcoef, /**< variable bound coefficient */
11282  SCIP_Real vlbconst, /**< variable bound constant */
11283  int duration /**< duration of the variable bound variable */
11284  )
11285 {
11286  if( SCIPisEQ(scip, vlbcoef, 1.0) )
11287  {
11288  if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11289  {
11290  /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11291  return TRUE;
11292  }
11293  }
11294  else
11295  {
11296  SCIP_Real bound;
11297 
11298  bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11299 
11300  if( SCIPisLT(scip, vlbcoef, 1.0) )
11301  {
11302  SCIP_Real ub;
11303 
11304  ub = SCIPvarGetUbLocal(vlbvar);
11305 
11306  /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11307  if( SCIPisLE(scip, ub, bound) )
11308  return TRUE;
11309  }
11310  else
11311  {
11312  SCIP_Real lb;
11313 
11314  assert(SCIPisGT(scip, vlbcoef, 1.0));
11315 
11316  lb = SCIPvarGetLbLocal(vlbvar);
11317 
11318  /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11319  if( SCIPisGE(scip, lb, bound) )
11320  return TRUE;
11321  }
11322  }
11323 
11324  return FALSE;
11325 }
11326 
11327 /** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11328  * job corresponding to variable which is bounded (var)
11329  *
11330  * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11331  */
11332 static
11334  SCIP* scip, /**< SCIP data structure */
11335  SCIP_VAR* var, /**< variable which is bound from above */
11336  SCIP_Real vubcoef, /**< variable bound coefficient */
11337  SCIP_Real vubconst, /**< variable bound constant */
11338  int duration /**< duration of the variable which is bounded from above */
11339  )
11340 {
11341  SCIP_Real vlbcoef;
11342  SCIP_Real vlbconst;
11343 
11344  /* convert the variable upper bound into an variable lower bound */
11345  vlbcoef = 1.0 / vubcoef;
11346  vlbconst = -vubconst / vubcoef;
11347 
11348  return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11349 }
11350 
11351 /** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11352  * others an index larger than the number if active variables
11353  */
11354 static
11356  SCIP* scip, /**< SCIP data structure */
11357  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11358  SCIP_VAR* var, /**< variable for which we want the index */
11359  int* idx /**< pointer to store the index */
11360  )
11361 {
11362  (*idx) = SCIPvarGetProbindex(var);
11363 
11364  if( (*idx) == -1 )
11365  {
11366  if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11367  {
11368  (*idx) = SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var);
11369  }
11370  else
11371  {
11372  int pos;
11373  int v;
11374 
11375  /**@todo we might want to add the aggregation path to graph */
11376 
11377  /* check if we have to realloc memory */
11378  if( tcliquegraph->size == tcliquegraph->nnodes )
11379  {
11380  int size;
11381 
11382  size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11383  tcliquegraph->size = size;
11384 
11385  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11386  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11387  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11388  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11389  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11390 
11391  for( v = 0; v < tcliquegraph->nnodes; ++v )
11392  {
11393  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11394  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11395  }
11396  }
11397  assert(tcliquegraph->nnodes < tcliquegraph->size);
11398 
11399  pos = tcliquegraph->nnodes;
11400  assert(pos >= 0);
11401 
11402  tcliquegraph->durations[pos] = 0;
11403  tcliquegraph->weights[pos] = 0;
11404  tcliquegraph->vars[pos] = var;
11405 
11406  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11407  BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11408 
11409  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11410  BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11411 
11412  SCIP_CALL( SCIPhashmapInsertInt(tcliquegraph->varmap, (void*)var, pos) );
11413 
11414  tcliquegraph->nnodes++;
11415 
11416  for( v = 0; v < tcliquegraph->nnodes; ++v )
11417  {
11418  tcliquegraph->precedencematrix[v][pos] = 0;
11419  tcliquegraph->demandmatrix[v][pos] = 0;
11420  }
11421 
11422  (*idx) = tcliquegraph->nnodes;
11423  }
11424  }
11425  else
11426  {
11427  assert(*idx == SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var));
11428  }
11429 
11430  assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11431 
11432  return SCIP_OKAY;
11433 }
11434 
11435 /** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11436  *
11437  * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11438  * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11439  *
11440  * (i) b = 1 and c >= d
11441  * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11442  * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11443  *
11444  */
11445 static
11447  SCIP* scip, /**< SCIP data structure */
11448  TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11449  )
11450 {
11451  SCIP_VAR** vars;
11452  int nvars;
11453  int v;
11454 
11455  vars = SCIPgetVars(scip);
11456  nvars = SCIPgetNVars(scip);
11457 
11458  /* try to project each arc of the variable bound graph to precedence condition */
11459  for( v = 0; v < nvars; ++v )
11460  {
11461  SCIP_VAR** vbdvars;
11462  SCIP_VAR* var;
11463  SCIP_Real* vbdcoefs;
11464  SCIP_Real* vbdconsts;
11465  int nvbdvars;
11466  int idx1;
11467  int b;
11468 
11469  var = vars[v];
11470  assert(var != NULL);
11471 
11472  SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11473  assert(idx1 >= 0);
11474 
11475  if( tcliquegraph->durations[idx1] == 0 )
11476  continue;
11477 
11478  vbdvars = SCIPvarGetVlbVars(var);
11479  vbdcoefs = SCIPvarGetVlbCoefs(var);
11480  vbdconsts = SCIPvarGetVlbConstants(var);
11481  nvbdvars = SCIPvarGetNVlbs(var);
11482 
11483  for( b = 0; b < nvbdvars; ++b )
11484  {
11485  int idx2;
11486 
11487  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11488  assert(idx2 >= 0);
11489 
11490  if( tcliquegraph->durations[idx2] == 0 )
11491  continue;
11492 
11493  if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11494  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11495  }
11496 
11497  vbdvars = SCIPvarGetVubVars(var);
11498  vbdcoefs = SCIPvarGetVubCoefs(var);
11499  vbdconsts = SCIPvarGetVubConstants(var);
11500  nvbdvars = SCIPvarGetNVubs(var);
11501 
11502  for( b = 0; b < nvbdvars; ++b )
11503  {
11504  int idx2;
11505 
11506  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11507  assert(idx2 >= 0);
11508 
11509  if( tcliquegraph->durations[idx2] == 0 )
11510  continue;
11511 
11512  if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11513  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11514  }
11515 
11516  for( b = v+1; b < nvars; ++b )
11517  {
11518  int idx2;
11519 
11520  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11521  assert(idx2 >= 0);
11522 
11523  if( tcliquegraph->durations[idx2] == 0 )
11524  continue;
11525 
11526  /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11527  if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11528  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11529 
11530  /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11531  if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11532  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11533  }
11534  }
11535 
11536  return SCIP_OKAY;
11537 }
11538 
11539 /** compute the transitive closer of the given graph and the number of in and out arcs */
11540 static
11541 void transitiveClosure(
11542  SCIP_Bool** adjmatrix, /**< adjacent matrix */
11543  int* ninarcs, /**< array to store the number of in arcs */
11544  int* noutarcs, /**< array to store the number of out arcs */
11545  int nnodes /**< number if nodes */
11546  )
11547 {
11548  int i;
11549  int j;
11550  int k;
11551 
11552  for( i = 0; i < nnodes; ++i )
11553  {
11554  for( j = 0; j < nnodes; ++j )
11555  {
11556  if( adjmatrix[i][j] )
11557  {
11558  ninarcs[j]++;
11559  noutarcs[i]++;
11560 
11561  for( k = 0; k < nnodes; ++k )
11562  {
11563  if( adjmatrix[j][k] )
11564  adjmatrix[i][k] = TRUE;
11565  }
11566  }
11567  }
11568  }
11569 }
11570 
11571 /** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11572 static
11574  SCIP* scip, /**< SCIP data structure */
11575  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11576  SCIP_CONS** conss, /**< array of cumulative constraints */
11577  int nconss /**< number of cumulative constraints */
11578  )
11579 {
11580  int c;
11581 
11582  /* use the cumulative constraints to initialize the none overlapping graph */
11583  for( c = 0; c < nconss; ++c )
11584  {
11585  SCIP_CONSDATA* consdata;
11586  SCIP_VAR** vars;
11587  int* demands;
11588  int capacity;
11589  int nvars;
11590  int i;
11591 
11592  consdata = SCIPconsGetData(conss[c]);
11593  assert(consdata != NULL);
11594 
11595  vars = consdata->vars;
11596  demands = consdata->demands;
11597 
11598  nvars = consdata->nvars;
11599  capacity = consdata->capacity;
11600 
11601  SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11602 
11603  /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11604  for( i = 0; i < nvars; ++i )
11605  {
11606  int idx1;
11607  int j;
11608 
11609  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11610  assert(idx1 >= 0);
11611 
11612  if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11613  continue;
11614 
11615  for( j = i+1; j < nvars; ++j )
11616  {
11617  assert(consdata->durations[j] > 0);
11618 
11619  if( demands[i] + demands[j] > capacity )
11620  {
11621  int idx2;
11622  int est1;
11623  int est2;
11624  int lct1;
11625  int lct2;
11626 
11627  /* check if the effective horizon is large enough */
11628  est1 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[i]));
11629  est2 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[j]));
11630 
11631  /* at least one of the jobs needs to start at hmin or later */
11632  if( est1 < consdata->hmin && est2 < consdata->hmin )
11633  continue;
11634 
11635  lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11636  lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11637 
11638  /* at least one of the jobs needs to finish not later then hmin */
11639  if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11640  continue;
11641 
11642  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11643  assert(idx2 >= 0);
11644  assert(idx1 != idx2);
11645 
11646  if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11647  continue;
11648 
11649  SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11650 
11651  assert(tcliquegraph->durations[idx1] > 0);
11652  assert(tcliquegraph->durations[idx2] > 0);
11653 
11654  tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11655  tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11656  }
11657  }
11658  }
11659  }
11660 
11661  return SCIP_OKAY;
11662 }
11663 
11664 /** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11665  * of jobs cannot run in parallel
11666  */
11667 static
11669  SCIP* scip, /**< SCIP data structure */
11670  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11671  SCIP_CONS** conss, /**< array of cumulative constraints */
11672  int nconss /**< number of cumulative constraints */
11673  )
11674 {
11675  assert(scip != NULL);
11676  assert(tcliquegraph != NULL);
11677 
11678  /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11679  SCIP_CALL( projectVbd(scip, tcliquegraph) );
11680 
11681  /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11682  transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11683 
11684  /* constraints non-overlapping graph */
11685  SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11686 
11687  return SCIP_OKAY;
11688 }
11689 
11690 /** create cumulative constraint from conflict set */
11691 static
11693  SCIP* scip, /**< SCIP data structure */
11694  const char* name, /**< constraint name */
11695  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11696  int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11697  int ncliquenodes /**< number of nodes in the clique */
11698  )
11699 {
11700  SCIP_CONS* cons;
11701  SCIP_VAR** vars;
11702  int* durations;
11703  int* demands;
11704  int v;
11705 
11706  SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11707  SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11708  SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11709 
11710  SCIPsortInt(cliquenodes, ncliquenodes);
11711 
11712  /* collect variables, durations, and demands */
11713  for( v = 0; v < ncliquenodes; ++v )
11714  {
11715  durations[v] = tcliquegraph->durations[cliquenodes[v]];
11716  assert(durations[v] > 0);
11717  demands[v] = 1;
11718  vars[v] = tcliquegraph->vars[cliquenodes[v]];
11719  }
11720 
11721  /* create (unary) cumulative constraint */
11722  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11724 
11725  SCIP_CALL( SCIPaddCons(scip, cons) );
11726  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11727 
11728  /* free buffers */
11729  SCIPfreeBufferArray(scip, &demands);
11730  SCIPfreeBufferArray(scip, &durations);
11731  SCIPfreeBufferArray(scip, &vars);
11732 
11733  return SCIP_OKAY;
11734 }
11735 
11736 /** search for cumulative constrainst */
11737 static
11739  SCIP* scip, /**< SCIP data structure */
11740  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11741  int* naddconss /**< pointer to store the number of added constraints */
11742  )
11743 {
11744  TCLIQUE_STATUS tcliquestatus;
11745  SCIP_Bool* precedencerow;
11746  SCIP_Bool* precedencecol;
11747  SCIP_Bool* demandrow;
11748  SCIP_Bool* demandcol;
11749  SCIP_HASHTABLE* covered;
11750  int* cliquenodes;
11751  int ncliquenodes;
11752  int cliqueweight;
11753  int ntreenodes;
11754  int nnodes;
11755  int nconss;
11756  int v;
11757 
11758  nnodes = tcliquegraph->nnodes;
11759  nconss = 0;
11760 
11761  /* initialize the weight of each job with its duration */
11762  for( v = 0; v < nnodes; ++v )
11763  {
11764  tcliquegraph->weights[v] = tcliquegraph->durations[v];
11765  }
11766 
11767  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11768  SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11769  SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11770  SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11771  SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11772 
11773  /* create a hash table to store all start time variables which are already covered by at least one clique */
11774  SCIP_CALL( SCIPhashtableCreate(&covered, SCIPblkmem(scip), nnodes,
11775  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11776 
11777  /* for each variables/job we are ... */
11778  for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11779  {
11780  char name[SCIP_MAXSTRLEN];
11781  int c;
11782 
11783  /* jobs with zero durations are skipped */
11784  if( tcliquegraph->durations[v] == 0 )
11785  continue;
11786 
11787  /* check if the start time variable is already covered by at least one clique */
11788  if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11789  continue;
11790 
11791  SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11792 
11793  /* temporarily remove the connection via the precedence graph */
11794  for( c = 0; c < nnodes; ++c )
11795  {
11796  precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11797  precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11798 
11799  demandrow[c] = tcliquegraph->demandmatrix[v][c];
11800  demandcol[c] = tcliquegraph->demandmatrix[c][v];
11801 
11802 #if 0
11803  if( precedencerow[c] || precedencecol[c] )
11804  {
11805  tcliquegraph->demandmatrix[v][c] = FALSE;
11806  tcliquegraph->demandmatrix[c][v] = FALSE;
11807  }
11808 #endif
11809 
11810  tcliquegraph->precedencematrix[c][v] = FALSE;
11811  tcliquegraph->precedencematrix[v][c] = FALSE;
11812  }
11813 
11814  /* find (heuristically) maximum cliques which includes node v */
11815  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11816  tcliquegraph, tcliqueNewsolClique, NULL,
11817  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11818  10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11819 
11820  SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11821 
11822  if( ncliquenodes == 1 )
11823  continue;
11824 
11825  /* construct constraint name */
11826  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11827 
11828  SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11829  nconss++;
11830 
11831  /* all start time variable to covered hash table */
11832  for( c = 0; c < ncliquenodes; ++c )
11833  {
11834  SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11835  }
11836 
11837  /* copy the precedence relations back */
11838  for( c = 0; c < nnodes; ++c )
11839  {
11840  tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11841  tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11842 
11843  tcliquegraph->demandmatrix[v][c] = demandrow[c];
11844  tcliquegraph->demandmatrix[c][v] = demandcol[c];
11845  }
11846  }
11847 
11848  SCIPhashtableFree(&covered);
11849 
11850  SCIPfreeBufferArray(scip, &demandcol);
11851  SCIPfreeBufferArray(scip, &demandrow);
11852  SCIPfreeBufferArray(scip, &precedencecol);
11853  SCIPfreeBufferArray(scip, &precedencerow);
11854  SCIPfreeBufferArray(scip, &cliquenodes);
11855 
11856  (*naddconss) += nconss;
11857 
11858  /* for the statistic we count the number added disjunctive constraints */
11859  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11860 
11861  return SCIP_OKAY;
11862 }
11863 
11864 /** create precedence constraint (as variable bound constraint */
11865 static
11867  SCIP* scip, /**< SCIP data structure */
11868  const char* name, /**< constraint name */
11869  SCIP_VAR* var, /**< variable x that has variable bound */
11870  SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11871  int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11872  )
11873 {
11874  SCIP_CONS* cons;
11875 
11876  /* create variable bound constraint */
11877  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11879 
11880  SCIPdebugPrintCons(scip, cons, NULL);
11881 
11882  /* add constraint to problem and release it */
11883  SCIP_CALL( SCIPaddCons(scip, cons) );
11884  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11885 
11886  return SCIP_OKAY;
11887 }
11888 
11889 /** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11890 static
11892  SCIP* scip, /**< SCIP data structure */
11893  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11894  int source, /**< index of the source node */
11895  int sink, /**< index of the sink node */
11896  int* naddconss /**< pointer to store the number of added constraints */
11897  )
11898 {
11899  TCLIQUE_WEIGHT cliqueweight;
11900  TCLIQUE_STATUS tcliquestatus;
11901  SCIP_VAR** vars;
11902  int* cliquenodes;
11903  int nnodes;
11904  int lct;
11905  int est;
11906  int i;
11907 
11908  int ntreenodes;
11909  int ncliquenodes;
11910 
11911  /* check if source and sink are connencted */
11912  if( !tcliquegraph->precedencematrix[source][sink] )
11913  return SCIP_OKAY;
11914 
11915  nnodes = tcliquegraph->nnodes;
11916  vars = tcliquegraph->vars;
11917 
11918  /* reset the weights to zero */
11919  BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11920 
11921  /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11922  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11923  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[sink]));
11924 
11925  /* weight all jobs which run for sure between source and sink with their duration */
11926  for( i = 0; i < nnodes; ++i )
11927  {
11928  SCIP_VAR* var;
11929  int duration;
11930 
11931  var = vars[i];
11932  assert(var != NULL);
11933 
11934  duration = tcliquegraph->durations[i];
11935 
11936  if( i == source || i == sink )
11937  {
11938  /* source and sink are not weighted */
11939  tcliquegraph->weights[i] = 0;
11940  }
11941  else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11942  {
11943  /* job i runs after source and before sink */
11944  tcliquegraph->weights[i] = duration;
11945  }
11946  else if( lct <= SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var))
11947  && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11948  {
11949  /* job i run in between due the bounds of the start time variables */
11950  tcliquegraph->weights[i] = duration;
11951  }
11952  else
11953  tcliquegraph->weights[i] = 0;
11954  }
11955 
11956  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11957 
11958  /* find (heuristically) maximum cliques */
11959  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11960  tcliquegraph, tcliqueNewsolClique, NULL,
11961  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11962  10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11963 
11964  if( ncliquenodes > 1 )
11965  {
11966  char name[SCIP_MAXSTRLEN];
11967  int distance;
11968 
11969  /* construct constraint name */
11970  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11971 
11972  /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11973  * duration of the source job
11974  */
11975  distance = cliqueweight + tcliquegraph->durations[source];
11976 
11977  SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11978  (*naddconss)++;
11979  }
11980 
11981  SCIPfreeBufferArray(scip, &cliquenodes);
11982 
11983  return SCIP_OKAY;
11984 }
11985 
11986 /** search for precedence constraints
11987  *
11988  * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
11989  * corresponding two jobs
11990  */
11991 static
11993  SCIP* scip, /**< SCIP data structure */
11994  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11995  int* naddconss /**< pointer to store the number of added constraints */
11996  )
11997 {
11998  int* sources;
11999  int* sinks;
12000  int nconss;
12001  int nnodes;
12002  int nsources;
12003  int nsinks;
12004  int i;
12005 
12006  nnodes = tcliquegraph->nnodes;
12007  nconss = 0;
12008 
12009  nsources = 0;
12010  nsinks = 0;
12011 
12012  SCIP_CALL( SCIPallocBufferArray(scip, &sources, nnodes) );
12013  SCIP_CALL( SCIPallocBufferArray(scip, &sinks, nnodes) );
12014 
12015  /* first collect all sources and sinks */
12016  for( i = 0; i < nnodes; ++i )
12017  {
12018  if( tcliquegraph->ninarcs[i] == 0 )
12019  {
12020  sources[nsources] = i;
12021  nsources++;
12022  }
12023 
12024  if( tcliquegraph->ninarcs[i] == 0 )
12025  {
12026  sinks[nsinks] = i;
12027  nsinks++;
12028  }
12029  }
12030 
12031  /* compute for each node a minimum distance to each sources and each sink */
12032  for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
12033  {
12034  int j;
12035 
12036  for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
12037  {
12038  SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
12039  }
12040 
12041  for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
12042  {
12043  SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
12044  }
12045  }
12046 
12047  (*naddconss) += nconss;
12048 
12049  /* for the statistic we count the number added variable constraints */
12050  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
12051 
12052  SCIPfreeBufferArray(scip, &sinks);
12053  SCIPfreeBufferArray(scip, &sources);
12054 
12055  return SCIP_OKAY;
12056 }
12057 
12058 /** initialize the assumed durations for each variable */
12059 static
12061  SCIP* scip, /**< SCIP data structure */
12062  TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
12063  SCIP_CONS** conss, /**< cumulative constraints */
12064  int nconss /**< number of cumulative constraints */
12065  )
12066 {
12067  int c;
12068 
12069  /* use the cumulative structure to define the duration we are using for each job */
12070  for( c = 0; c < nconss; ++c )
12071  {
12072  SCIP_CONSDATA* consdata;
12073  SCIP_VAR** vars;
12074  int nvars;
12075  int v;
12076 
12077  consdata = SCIPconsGetData(conss[c]);
12078  assert(consdata != NULL);
12079 
12080  vars = consdata->vars;
12081  nvars = consdata->nvars;
12082 
12083  for( v = 0; v < nvars; ++v )
12084  {
12085  int idx;
12086 
12087  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12088  assert(idx >= 0);
12089 
12090  /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12091  * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12092  * general this is not the case. Therefore, the question would be which duration should be used?
12093  */
12094  tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12095  assert(tcliquegraph->durations[idx] > 0);
12096  }
12097  }
12098 
12099  return SCIP_OKAY;
12100 }
12101 
12102 /** create tclique graph */
12103 static
12105  SCIP* scip, /**< SCIP data structure */
12106  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12107  )
12108 {
12109  SCIP_VAR** vars;
12110  SCIP_HASHMAP* varmap;
12111  SCIP_Bool** precedencematrix;
12112  SCIP_Bool** demandmatrix;
12113  int* ninarcs;
12114  int* noutarcs;
12115  int* durations;
12116  int* weights;
12117  int nvars;
12118  int v;
12119 
12120  vars = SCIPgetVars(scip);
12121  nvars = SCIPgetNVars(scip);
12122 
12123  /* allocate memory for the tclique graph data structure */
12124  SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12125 
12126  /* create the variable mapping hash map */
12127  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
12128 
12129  /* each active variables get a node in the graph */
12130  SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12131 
12132  /* allocate memory for the projected variables bound graph and the none overlapping graph */
12133  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12134  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12135 
12136  /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12137  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12138  BMSclearMemoryArray(weights, nvars);
12139 
12140  /* array to store the number of in arc of the precedence graph */
12141  SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12142  BMSclearMemoryArray(ninarcs, nvars);
12143 
12144  /* array to store the number of out arc of the precedence graph */
12145  SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12146  BMSclearMemoryArray(noutarcs, nvars);
12147 
12148  /* array to store the used duration for each node */
12149  SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12150  BMSclearMemoryArray(durations, nvars);
12151 
12152  for( v = 0; v < nvars; ++v )
12153  {
12154  SCIP_VAR* var;
12155 
12156  var = vars[v];
12157  assert(var != NULL);
12158 
12159  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12160  BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12161 
12162  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12163  BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12164 
12165  /* insert all active variables into the garph */
12166  assert(SCIPvarGetProbindex(var) == v);
12167  SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)var, v) );
12168  }
12169 
12170  (*tcliquegraph)->nnodes = nvars;
12171  (*tcliquegraph)->varmap = varmap;
12172  (*tcliquegraph)->precedencematrix = precedencematrix;
12173  (*tcliquegraph)->demandmatrix = demandmatrix;
12174  (*tcliquegraph)->weights = weights;
12175  (*tcliquegraph)->ninarcs = ninarcs;
12176  (*tcliquegraph)->noutarcs = noutarcs;
12177  (*tcliquegraph)->durations = durations;
12178  (*tcliquegraph)->size = nvars;
12179 
12180  return SCIP_OKAY;
12181 }
12182 
12183 /** frees the tclique graph */
12184 static
12185 void freeTcliqueGraph(
12186  SCIP* scip, /**< SCIP data structure */
12187  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12188  )
12189 {
12190  int v;
12191 
12192  for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12193  {
12194  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12195  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12196  }
12197 
12198  SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12199  SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12200  SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12201  SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12202  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12203  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12204  SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12205  SCIPhashmapFree(&(*tcliquegraph)->varmap);
12206 
12207  SCIPfreeBuffer(scip, tcliquegraph);
12208 }
12209 
12210 /** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12211  * constrains (disjunctive constraint)
12212  */
12213 static
12215  SCIP* scip, /**< SCIP data structure */
12216  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12217  SCIP_CONS** conss, /**< array of cumulative constraints */
12218  int nconss, /**< number of cumulative constraints */
12219  int* naddconss /**< pointer to store the number of added constraints */
12220  )
12221 {
12222  TCLIQUE_GRAPH* tcliquegraph;
12223 
12224  /* create tclique graph */
12225  SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12226 
12227  /* define for each job a duration */
12228  SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12229 
12230  /* constuct incompatibility graph */
12231  SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12232 
12233  /* search for new precedence constraints */
12234  if( conshdlrdata->detectvarbounds )
12235  {
12236  SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12237  }
12238 
12239  /* search for new cumulative constraints */
12240  if( conshdlrdata->detectdisjunctive )
12241  {
12242  SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12243  }
12244 
12245  /* free tclique graph data structure */
12246  freeTcliqueGraph(scip, &tcliquegraph);
12247 
12248  return SCIP_OKAY;
12249 }
12250 
12251 /** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12252 static
12254  SCIP_CONSDATA* consdata /**< cumulative constraint data */
12255  )
12256 {
12257  SCIP_VAR** vars;
12258  int nvars;
12259  int v;
12260 
12261  if( consdata->validsignature )
12262  return;
12263 
12264  vars = consdata->vars;
12265  nvars = consdata->nvars;
12266 
12267  for( v = 0; v < nvars; ++v )
12268  {
12269  consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12270  }
12271 
12272  consdata->validsignature = TRUE;
12273 }
12274 
12275 /** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12276 static
12277 SCIP_DECL_SORTINDCOMP(consdataCompVar)
12278 { /*lint --e{715}*/
12279  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12280 
12281  assert(consdata != NULL);
12282  assert(0 <= ind1 && ind1 < consdata->nvars);
12283  assert(0 <= ind2 && ind2 < consdata->nvars);
12284 
12285  return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12286 }
12287 
12288 /** run a pairwise comparison */
12289 static
12291  SCIP* scip, /**< SCIP data structure */
12292  SCIP_CONS** conss, /**< array of cumulative constraints */
12293  int nconss, /**< number of cumulative constraints */
12294  int* ndelconss /**< pointer to store the number of deletedconstraints */
12295  )
12296 {
12297  int i;
12298  int j;
12299 
12300  for( i = 0; i < nconss; ++i )
12301  {
12302  SCIP_CONSDATA* consdata0;
12303  SCIP_CONS* cons0;
12304 
12305  cons0 = conss[i];
12306  assert(cons0 != NULL);
12307 
12308  consdata0 = SCIPconsGetData(cons0);
12309  assert(consdata0 != NULL);
12310 
12311  consdataCalcSignature(consdata0);
12312  assert(consdata0->validsignature);
12313 
12314  for( j = i+1; j < nconss; ++j )
12315  {
12316  SCIP_CONSDATA* consdata1;
12317  SCIP_CONS* cons1;
12318 
12319  cons1 = conss[j];
12320  assert(cons1 != NULL);
12321 
12322  consdata1 = SCIPconsGetData(cons1);
12323  assert(consdata1 != NULL);
12324 
12325  if( consdata0->capacity != consdata1->capacity )
12326  continue;
12327 
12328  consdataCalcSignature(consdata1);
12329  assert(consdata1->validsignature);
12330 
12331  if( (consdata1->signature & (~consdata0->signature)) == 0 )
12332  {
12333  SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12334  SCIPswapPointers((void**)&cons0, (void**)&cons1);
12335  assert((consdata0->signature & (~consdata1->signature)) == 0);
12336  }
12337 
12338  if( (consdata0->signature & (~consdata1->signature)) == 0 )
12339  {
12340  int* perm0;
12341  int* perm1;
12342  int v0;
12343  int v1;
12344 
12345  if( consdata0->nvars > consdata1->nvars )
12346  continue;
12347 
12348  if( consdata0->hmin < consdata1->hmin )
12349  continue;
12350 
12351  if( consdata0->hmax > consdata1->hmax )
12352  continue;
12353 
12354  SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12355  SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12356 
12357  /* call sorting method */
12358  SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12359  SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12360 
12361  for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12362  {
12363  SCIP_VAR* var0;
12364  SCIP_VAR* var1;
12365  int idx0;
12366  int idx1;
12367  int comp;
12368 
12369  idx0 = perm0[v0];
12370  idx1 = perm1[v1];
12371 
12372  var0 = consdata0->vars[idx0];
12373 
12374  var1 = consdata1->vars[idx1];
12375 
12376  comp = SCIPvarCompare(var0, var1);
12377 
12378  if( comp == 0 )
12379  {
12380  int duration0;
12381  int duration1;
12382  int demand0;
12383  int demand1;
12384 
12385  demand0 = consdata0->demands[idx0];
12386  duration0 = consdata0->durations[idx0];
12387 
12388  demand1 = consdata1->demands[idx1];
12389  duration1 = consdata1->durations[idx1];
12390 
12391  if( demand0 != demand1 )
12392  break;
12393 
12394  if( duration0 != duration1 )
12395  break;
12396 
12397  v0++;
12398  v1++;
12399  }
12400  else if( comp > 0 )
12401  v1++;
12402  else
12403  break;
12404  }
12405 
12406  if( v0 == consdata0->nvars )
12407  {
12408  if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12409  {
12410  initializeLocks(consdata1, TRUE);
12411  }
12412 
12413  /* coverity[swapped_arguments] */
12414  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12415 
12416  SCIP_CALL( SCIPdelCons(scip, cons0) );
12417  (*ndelconss)++;
12418  }
12419 
12420  SCIPfreeBufferArray(scip, &perm1);
12421  SCIPfreeBufferArray(scip, &perm0);
12422  }
12423  }
12424  }
12425 
12426  return SCIP_OKAY;
12427 }
12428 
12429 /** strengthen the variable bounds using the cumulative condition */
12430 static
12432  SCIP* scip, /**< SCIP data structure */
12433  SCIP_CONS* cons, /**< constraint to propagate */
12434  int* nchgbds, /**< pointer to store the number of changed bounds */
12435  int* naddconss /**< pointer to store the number of added constraints */
12436  )
12437 {
12438  SCIP_CONSDATA* consdata;
12439  SCIP_VAR** vars;
12440  int* durations;
12441  int* demands;
12442  int capacity;
12443  int nvars;
12444  int nconss;
12445  int i;
12446 
12447  consdata = SCIPconsGetData(cons);
12448  assert(consdata != NULL);
12449 
12450  /* check if the variable bounds got already strengthen by the cumulative constraint */
12451  if( consdata->varbounds )
12452  return SCIP_OKAY;
12453 
12454  vars = consdata->vars;
12455  durations = consdata->durations;
12456  demands = consdata->demands;
12457  capacity = consdata->capacity;
12458  nvars = consdata->nvars;
12459 
12460  nconss = 0;
12461 
12462  for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12463  {
12464  SCIP_VAR** vbdvars;
12465  SCIP_VAR* var;
12466  SCIP_Real* vbdcoefs;
12467  SCIP_Real* vbdconsts;
12468  int nvbdvars;
12469  int b;
12470  int j;
12471 
12472  var = consdata->vars[i];
12473  assert(var != NULL);
12474 
12475  vbdvars = SCIPvarGetVlbVars(var);
12476  vbdcoefs = SCIPvarGetVlbCoefs(var);
12477  vbdconsts = SCIPvarGetVlbConstants(var);
12478  nvbdvars = SCIPvarGetNVlbs(var);
12479 
12480  for( b = 0; b < nvbdvars; ++b )
12481  {
12482  if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12483  {
12484  if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12485  {
12486  for( j = 0; j < nvars; ++j )
12487  {
12488  if( vars[j] == vbdvars[b] )
12489  break;
12490  }
12491  if( j == nvars )
12492  continue;
12493 
12494  if( demands[i] + demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12495  {
12496  SCIP_Bool infeasible;
12497  char name[SCIP_MAXSTRLEN];
12498  int nlocalbdchgs;
12499 
12500  SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12501 
12502  /* construct constraint name */
12503  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12504 
12505  SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12506  nconss++;
12507 
12508  SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12509  assert(!infeasible);
12510 
12511  (*nchgbds) += nlocalbdchgs;
12512  }
12513  }
12514  }
12515  }
12516  }
12517 
12518  (*naddconss) += nconss;
12519 
12520  consdata->varbounds = TRUE;
12521 
12522  return SCIP_OKAY;
12523 }
12524 
12525 /** helper function to enforce constraints */
12526 static
12528  SCIP* scip, /**< SCIP data structure */
12529  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
12530  SCIP_CONS** conss, /**< constraints to process */
12531  int nconss, /**< number of constraints */
12532  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
12533  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
12534  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
12535  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
12536  )
12537 {
12538  SCIP_CONSHDLRDATA* conshdlrdata;
12539 
12540  assert(conshdlr != NULL);
12541  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12542  assert(nconss == 0 || conss != NULL);
12543  assert(result != NULL);
12544 
12545  if( solinfeasible )
12546  {
12547  *result = SCIP_INFEASIBLE;
12548  return SCIP_OKAY;
12549  }
12550 
12551  SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12552  sol == NULL ? "LP" : "relaxation");
12553 
12554  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12555  assert(conshdlrdata != NULL);
12556 
12557  (*result) = SCIP_FEASIBLE;
12558 
12559  if( conshdlrdata->usebinvars )
12560  {
12561  SCIP_Bool separated;
12562  SCIP_Bool cutoff;
12563  int c;
12564 
12565  separated = FALSE;
12566 
12567  /* first check if a constraints is violated */
12568  for( c = 0; c < nusefulconss; ++c )
12569  {
12570  SCIP_CONS* cons;
12571  SCIP_Bool violated;
12572 
12573  cons = conss[c];
12574  assert(cons != NULL);
12575 
12576  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12577 
12578  if( !violated )
12579  continue;
12580 
12581  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12582  if ( cutoff )
12583  {
12584  *result = SCIP_CUTOFF;
12585  return SCIP_OKAY;
12586  }
12587  }
12588 
12589  for( ; c < nconss && !separated; ++c )
12590  {
12591  SCIP_CONS* cons;
12592  SCIP_Bool violated;
12593 
12594  cons = conss[c];
12595  assert(cons != NULL);
12596 
12597  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12598 
12599  if( !violated )
12600  continue;
12601 
12602  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12603  if ( cutoff )
12604  {
12605  *result = SCIP_CUTOFF;
12606  return SCIP_OKAY;
12607  }
12608  }
12609 
12610  if( separated )
12611  (*result) = SCIP_SEPARATED;
12612  }
12613  else
12614  {
12615  SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12616  }
12617 
12618  return SCIP_OKAY;
12619 }
12620 
12621 /**@} */
12622 
12623 
12624 /**@name Callback methods of constraint handler
12625  *
12626  * @{
12627  */
12628 
12629 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12630 static
12631 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12632 { /*lint --e{715}*/
12633  assert(scip != NULL);
12634  assert(conshdlr != NULL);
12635  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12636 
12637  /* call inclusion method of constraint handler */
12639 
12641 
12642  *valid = TRUE;
12643 
12644  return SCIP_OKAY;
12645 }
12646 
12647 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12648 static
12649 SCIP_DECL_CONSFREE(consFreeCumulative)
12650 { /*lint --e{715}*/
12651  SCIP_CONSHDLRDATA* conshdlrdata;
12652 
12653  assert(conshdlr != NULL);
12654  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12655 
12656  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12657  assert(conshdlrdata != NULL);
12658 
12659 #ifdef SCIP_STATISTIC
12660  if( !conshdlrdata->iscopy )
12661  {
12662  /* statisitc output if SCIP_STATISTIC is defined */
12663  SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12664  conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12665  SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12666  conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12667  SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12668  conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12669  }
12670 #endif
12671 
12672  conshdlrdataFree(scip, &conshdlrdata);
12673 
12674  SCIPconshdlrSetData(conshdlr, NULL);
12675 
12676  return SCIP_OKAY;
12677 }
12678 
12679 
12680 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12681 static
12682 SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12683 { /*lint --e{715}*/
12684  SCIP_CONSHDLRDATA* conshdlrdata;
12685  int c;
12686 
12687  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12688  assert(conshdlrdata != NULL);
12689 
12690  conshdlrdata->detectedredundant = FALSE;
12691 
12692  for( c = 0; c < nconss; ++c )
12693  {
12694  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12695  * hmax)
12696  */
12697  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12698  }
12699 
12700  return SCIP_OKAY;
12701 }
12702 
12703 
12704 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12705 #ifdef SCIP_STATISTIC
12706 static
12707 SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12708 { /*lint --e{715}*/
12709  SCIP_CONSHDLRDATA* conshdlrdata;
12710  int c;
12711 
12712  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12713  assert(conshdlrdata != NULL);
12714 
12715  for( c = 0; c < nconss; ++c )
12716  {
12717  SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12718 
12719 #if 0
12720  SCIP_CALL( SCIPvisualizeConsCumulative(scip, conss[c]) );
12721 #endif
12722  }
12723 
12724  if( !conshdlrdata->iscopy )
12725  {
12726  SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12727  SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12728  SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12729  SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12730  SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12731  SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12732  SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12733  SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12734  SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12735  }
12736 
12737  return SCIP_OKAY;
12738 }
12739 #endif
12740 
12741 
12742 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12743 static
12744 SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12745 { /*lint --e{715}*/
12746  SCIP_CONSDATA* consdata;
12747  int c;
12748 
12749  assert(conshdlr != NULL);
12750  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12751 
12752  /* release the rows of all constraints */
12753  for( c = 0; c < nconss; ++c )
12754  {
12755  consdata = SCIPconsGetData(conss[c]);
12756  assert(consdata != NULL);
12757 
12758  /* free rows */
12759  SCIP_CALL( consdataFreeRows(scip, &consdata) );
12760  }
12761 
12762  return SCIP_OKAY;
12763 }
12764 
12765 /** frees specific constraint data */
12766 static
12767 SCIP_DECL_CONSDELETE(consDeleteCumulative)
12768 { /*lint --e{715}*/
12769  assert(conshdlr != NULL);
12770  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12771  assert(consdata != NULL );
12772  assert(*consdata != NULL );
12773 
12774  /* if constraint belongs to transformed problem space, drop bound change events on variables */
12775  if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12776  {
12777  SCIP_CONSHDLRDATA* conshdlrdata;
12778 
12779  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12780  assert(conshdlrdata != NULL);
12781 
12782  SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12783  }
12784 
12785  /* free cumulative constraint data */
12786  SCIP_CALL( consdataFree(scip, consdata) );
12787 
12788  return SCIP_OKAY;
12789 }
12790 
12791 /** transforms constraint data into data belonging to the transformed problem */
12792 static
12793 SCIP_DECL_CONSTRANS(consTransCumulative)
12794 { /*lint --e{715}*/
12795  SCIP_CONSHDLRDATA* conshdlrdata;
12796  SCIP_CONSDATA* sourcedata;
12797  SCIP_CONSDATA* targetdata;
12798 
12799  assert(conshdlr != NULL);
12800  assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
12801  assert(sourcecons != NULL);
12802  assert(targetcons != NULL);
12803 
12804  sourcedata = SCIPconsGetData(sourcecons);
12805  assert(sourcedata != NULL);
12806  assert(sourcedata->demandrows == NULL);
12807 
12808  SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12809 
12810  /* get event handler */
12811  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12812  assert(conshdlrdata != NULL);
12813  assert(conshdlrdata->eventhdlr != NULL);
12814 
12815  /* create constraint data for target constraint */
12816  SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12817  sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12818  sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12819 
12820  /* create target constraint */
12821  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12822  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12823  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12824  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12825  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12826 
12827  /* catch bound change events of variables */
12828  SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12829 
12830  return SCIP_OKAY;
12831 }
12832 
12833 /** LP initialization method of constraint handler */
12834 static
12835 SCIP_DECL_CONSINITLP(consInitlpCumulative)
12837  SCIP_CONSHDLRDATA* conshdlrdata;
12838  int c;
12839 
12840  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12841  assert(conshdlr != NULL);
12842  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12843  assert(conshdlrdata != NULL);
12844 
12845  *infeasible = FALSE;
12846 
12847  SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12848 
12849  if( conshdlrdata->usebinvars )
12850  {
12851  /* add rows to LP */
12852  for( c = 0; c < nconss && !(*infeasible); ++c )
12853  {
12854  assert(SCIPconsIsInitial(conss[c]));
12855  SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12856 
12857  if( conshdlrdata->cutsasconss )
12858  {
12859  SCIP_CALL( SCIPrestartSolve(scip) );
12860  }
12861  }
12862  }
12863 
12864  /**@todo if we want to use only the integer variables; only these will be in cuts
12865  * create some initial cuts, currently these are only separated */
12866 
12867  return SCIP_OKAY;
12868 }
12869 
12870 /** separation method of constraint handler for LP solutions */
12871 static
12872 SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12874  SCIP_CONSHDLRDATA* conshdlrdata;
12875  SCIP_Bool cutoff;
12876  SCIP_Bool separated;
12877  int c;
12878 
12879  SCIPdebugMsg(scip, "consSepalpCumulative\n");
12880 
12881  assert(conshdlr != NULL);
12882  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12883  assert(nconss == 0 || conss != NULL);
12884  assert(result != NULL);
12885  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12886  assert(conshdlrdata != NULL);
12887 
12888  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12889 
12890  cutoff = FALSE;
12891  separated = FALSE;
12892  (*result) = SCIP_DIDNOTRUN;
12893 
12894  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12895  return SCIP_OKAY;
12896 
12897  (*result) = SCIP_DIDNOTFIND;
12898 
12899  if( conshdlrdata->usebinvars )
12900  {
12901  /* check all useful cumulative constraints for feasibility */
12902  for( c = 0; c < nusefulconss && !cutoff; ++c )
12903  {
12904  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12905  }
12906 
12907  if( !cutoff && conshdlrdata->usecovercuts )
12908  {
12909  for( c = 0; c < nusefulconss; ++c )
12910  {
12911  SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12912  }
12913  }
12914  }
12915 
12916  if( conshdlrdata->sepaold )
12917  {
12918  /* separate cuts containing only integer variables */
12919  for( c = 0; c < nusefulconss; ++c )
12920  {
12921  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12922  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12923  }
12924  }
12925 
12926  if( cutoff )
12927  *result = SCIP_CUTOFF;
12928  else if( separated )
12929  *result = SCIP_SEPARATED;
12930 
12931  return SCIP_OKAY;
12932 }
12933 
12934 /** separation method of constraint handler for arbitrary primal solutions */
12935 static
12936 SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12937 { /*lint --e{715}*/
12938  SCIP_CONSHDLRDATA* conshdlrdata;
12939  SCIP_Bool cutoff;
12940  SCIP_Bool separated;
12941  int c;
12942 
12943  assert(conshdlr != NULL);
12944  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12945  assert(nconss == 0 || conss != NULL);
12946  assert(result != NULL);
12947 
12948  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12949  assert(conshdlrdata != NULL);
12950 
12951  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12952  return SCIP_OKAY;
12953 
12954  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12955 
12956  cutoff = FALSE;
12957  separated = FALSE;
12958  (*result) = SCIP_DIDNOTFIND;
12959 
12960  if( conshdlrdata->usebinvars )
12961  {
12962  /* check all useful cumulative constraints for feasibility */
12963  for( c = 0; c < nusefulconss && !cutoff; ++c )
12964  {
12965  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12966  }
12967 
12968  if( !cutoff && conshdlrdata->usecovercuts )
12969  {
12970  for( c = 0; c < nusefulconss; ++c )
12971  {
12972  SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12973  }
12974  }
12975  }
12976  if( conshdlrdata->sepaold )
12977  {
12978  /* separate cuts containing only integer variables */
12979  for( c = 0; c < nusefulconss; ++c )
12980  {
12981  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12982  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12983  }
12984  }
12985 
12986  if( cutoff )
12987  *result = SCIP_CUTOFF;
12988  else if( separated )
12989  *result = SCIP_SEPARATED;
12990 
12991  return SCIP_OKAY;
12992 }
12993 
12994 /** constraint enforcing method of constraint handler for LP solutions */
12995 static
12996 SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
12997 { /*lint --e{715}*/
12998  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
12999 
13000  return SCIP_OKAY;
13001 }
13002 
13003 /** constraint enforcing method of constraint handler for relaxation solutions */
13004 static
13005 SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
13006 { /*lint --e{715}*/
13007  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
13008 
13009  return SCIP_OKAY;
13010 }
13011 
13012 /** constraint enforcing method of constraint handler for pseudo solutions */
13013 static
13014 SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
13015 { /*lint --e{715}*/
13016  SCIP_CONSHDLRDATA* conshdlrdata;
13017 
13018  SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
13019 
13020  assert(conshdlr != NULL);
13021  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13022  assert(nconss == 0 || conss != NULL);
13023  assert(result != NULL);
13024 
13025  if( objinfeasible )
13026  {
13027  *result = SCIP_DIDNOTRUN;
13028  return SCIP_OKAY;
13029  }
13030 
13031  (*result) = SCIP_FEASIBLE;
13032 
13033  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13034  assert(conshdlrdata != NULL);
13035 
13036  SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
13037 
13038  return SCIP_OKAY;
13039 }
13040 
13041 /** feasibility check method of constraint handler for integral solutions */
13042 static
13043 SCIP_DECL_CONSCHECK(consCheckCumulative)
13044 { /*lint --e{715}*/
13045  int c;
13046 
13047  assert(conshdlr != NULL);
13048  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13049  assert(nconss == 0 || conss != NULL);
13050  assert(result != NULL);
13051 
13052  *result = SCIP_FEASIBLE;
13053 
13054  SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
13055 
13056  for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
13057  {
13058  SCIP_Bool violated = FALSE;
13059 
13060  SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
13061 
13062  if( violated )
13063  *result = SCIP_INFEASIBLE;
13064  }
13065 
13066  return SCIP_OKAY;
13067 }
13068 
13069 /** domain propagation method of constraint handler */
13070 static
13071 SCIP_DECL_CONSPROP(consPropCumulative)
13072 { /*lint --e{715}*/
13073  SCIP_CONSHDLRDATA* conshdlrdata;
13074  SCIP_Bool cutoff;
13075  int nchgbds;
13076  int ndelconss;
13077  int c;
13078 #if 0
13079  int naggrvars = 0;
13080 #endif
13081 
13082  SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
13083 
13084  assert(conshdlr != NULL);
13085  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13086  assert(nconss == 0 || conss != NULL);
13087  assert(result != NULL);
13088 
13089  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13090  assert(conshdlrdata != NULL);
13091 
13092  nchgbds = 0;
13093  ndelconss = 0;
13094  cutoff = FALSE;
13095  (*result) = SCIP_DIDNOTRUN;
13096 
13097  /* propgate all useful constraints */
13098  for( c = 0; c < nusefulconss && !cutoff; ++c )
13099  {
13100  SCIP_CONS* cons;
13101 
13102  cons = conss[c];
13103  assert(cons != NULL);
13104 
13105  if( SCIPgetDepth(scip) == 0 )
13106  {
13107 #if 0
13108  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13109  &nchgbds, &naggrvars, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13110 #else
13111  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13112  &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13113 #endif
13114  if( cutoff )
13115  break;
13116 
13117  if( SCIPconsIsDeleted(cons) )
13118  continue;
13119  }
13120 
13121  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13122  }
13123 
13124  if( !cutoff && nchgbds == 0 )
13125  {
13126  /* propgate all other constraints */
13127  for( c = nusefulconss; c < nconss && !cutoff; ++c )
13128  {
13129  SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13130  }
13131  }
13132 
13133 #if 0
13134  if( !cutoff && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 )
13135  {
13136  SCIP_CALL( propagateAllConss(scip, conss, nconss, TRUE, &nchgbds, &cutoff, NULL) );
13137  }
13138 #endif
13139 
13140  if( cutoff )
13141  {
13142  SCIPdebugMsg(scip, "detected infeasible\n");
13143  *result = SCIP_CUTOFF;
13144  }
13145  else if( nchgbds > 0 )
13146  {
13147  SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13148  *result = SCIP_REDUCEDDOM;
13149  }
13150  else
13151  *result = SCIP_DIDNOTFIND;
13152 
13153  return SCIP_OKAY;
13154 }
13155 
13156 /** presolving method of constraint handler */
13157 static
13158 SCIP_DECL_CONSPRESOL(consPresolCumulative)
13159 { /*lint --e{715}*/
13160  SCIP_CONSHDLRDATA* conshdlrdata;
13161  SCIP_CONS* cons;
13162  SCIP_Bool cutoff;
13163  SCIP_Bool unbounded;
13164  int oldnfixedvars;
13165  int oldnchgbds;
13166  int oldndelconss;
13167  int oldnaddconss;
13168  int oldnupgdconss;
13169  int oldnchgsides;
13170  int oldnchgcoefs;
13171  int c;
13172 
13173  assert(conshdlr != NULL);
13174  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13175  assert(scip != NULL);
13176  assert(result != NULL);
13177 
13178  SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13179 
13180  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13181  assert(conshdlrdata != NULL);
13182 
13183  *result = SCIP_DIDNOTRUN;
13184 
13185  oldnfixedvars = *nfixedvars;
13186  oldnchgbds = *nchgbds;
13187  oldnchgsides = *nchgsides;
13188  oldnchgcoefs = *nchgcoefs;
13189  oldnupgdconss = *nupgdconss;
13190  oldndelconss = *ndelconss;
13191  oldnaddconss = *naddconss;
13192  cutoff = FALSE;
13193  unbounded = FALSE;
13194 
13195  /* process constraints */
13196  for( c = 0; c < nconss && !cutoff; ++c )
13197  {
13198  cons = conss[c];
13199 
13200  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13201  * hmax)
13202  */
13203  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13204 
13205  if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13206  {
13207 #if 0
13208  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13209  nfixedvars, naggrvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13210 #else
13211  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13212  nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13213 #endif
13214 
13215  if( cutoff || unbounded )
13216  break;
13217 
13218  if( SCIPconsIsDeleted(cons) )
13219  continue;
13220  }
13221 
13222  /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13223  if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13224  {
13225  SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13226  }
13227 
13228  /* strengthen existing variable bounds using the cumulative condition */
13229  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13230  {
13231  SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13232  }
13233 
13234  /* propagate cumulative constraint */
13235  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13236  assert(checkDemands(scip, cons) || cutoff);
13237  }
13238 
13239  if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13240  {
13241  SCIP_CALL( propagateAllConss(scip, conss, nconss, FALSE, nfixedvars, &cutoff, NULL) );
13242  }
13243 
13244  /* only perform the detection of variable bounds and disjunctive constraint once */
13245  if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13246  && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13247  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13248  {
13249  /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13250  * propagation
13251  */
13252  SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13253  conshdlrdata->detectedredundant = TRUE;
13254  }
13255 
13256  if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13257  {
13258  SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13259  }
13260 
13261  SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13262  *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13263 
13264  if( cutoff )
13265  *result = SCIP_CUTOFF;
13266  else if( unbounded )
13267  *result = SCIP_UNBOUNDED;
13268  else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13269  || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13270  *result = SCIP_SUCCESS;
13271  else
13272  *result = SCIP_DIDNOTFIND;
13273 
13274  return SCIP_OKAY;
13275 }
13276 
13277 /** propagation conflict resolving method of constraint handler */
13278 static
13279 SCIP_DECL_CONSRESPROP(consRespropCumulative)
13280 { /*lint --e{715}*/
13281  SCIP_CONSHDLRDATA* conshdlrdata;
13282  SCIP_CONSDATA* consdata;
13283 
13284  assert(conshdlr != NULL);
13285  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13286  assert(scip != NULL);
13287  assert(result != NULL);
13288  assert(infervar != NULL);
13289  assert(bdchgidx != NULL);
13290 
13291  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13292  assert(conshdlrdata != NULL);
13293 
13294  /* process constraint */
13295  assert(cons != NULL);
13296 
13297  consdata = SCIPconsGetData(cons);
13298  assert(consdata != NULL);
13299 
13300  SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13301  SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13302  SCIPgetHminCumulative(scip, cons), SCIPgetHmaxCumulative(scip, cons));
13303 
13304  SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13305  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13306  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13307 
13308  return SCIP_OKAY;
13309 }
13310 
13311 /** variable rounding lock method of constraint handler */
13312 static
13313 SCIP_DECL_CONSLOCK(consLockCumulative)
13314 { /*lint --e{715}*/
13315  SCIP_CONSDATA* consdata;
13316  SCIP_VAR** vars;
13317  int v;
13318 
13319  SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13320 
13321  assert(scip != NULL);
13322  assert(cons != NULL);
13323  assert(locktype == SCIP_LOCKTYPE_MODEL);
13324 
13325  consdata = SCIPconsGetData(cons);
13326  assert(consdata != NULL);
13327 
13328  vars = consdata->vars;
13329  assert(vars != NULL);
13330 
13331  for( v = 0; v < consdata->nvars; ++v )
13332  {
13333  if( consdata->downlocks[v] && consdata->uplocks[v] )
13334  {
13335  /* the integer start variable should not get rounded in both direction */
13336  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
13337  }
13338  else if( consdata->downlocks[v] )
13339  {
13340  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
13341  }
13342  else if( consdata->uplocks[v] )
13343  {
13344  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
13345  }
13346  }
13347 
13348  return SCIP_OKAY;
13349 }
13350 
13351 
13352 /** constraint display method of constraint handler */
13353 static
13354 SCIP_DECL_CONSPRINT(consPrintCumulative)
13355 { /*lint --e{715}*/
13356  assert(scip != NULL);
13357  assert(conshdlr != NULL);
13358  assert(cons != NULL);
13359 
13360  consdataPrint(scip, SCIPconsGetData(cons), file);
13361 
13362  return SCIP_OKAY;
13363 }
13364 
13365 /** constraint copying method of constraint handler */
13366 static
13367 SCIP_DECL_CONSCOPY(consCopyCumulative)
13368 { /*lint --e{715}*/
13369  SCIP_CONSDATA* sourceconsdata;
13370  SCIP_VAR** sourcevars;
13371  SCIP_VAR** vars;
13372  const char* consname;
13373 
13374  int nvars;
13375  int v;
13376 
13377  sourceconsdata = SCIPconsGetData(sourcecons);
13378  assert(sourceconsdata != NULL);
13379 
13380  /* get variables of the source constraint */
13381  nvars = sourceconsdata->nvars;
13382  sourcevars = sourceconsdata->vars;
13383 
13384  (*valid) = TRUE;
13385 
13386  if( nvars == 0 )
13387  return SCIP_OKAY;
13388 
13389  /* allocate buffer array */
13390  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13391 
13392  for( v = 0; v < nvars && *valid; ++v )
13393  {
13394  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13395  assert(!(*valid) || vars[v] != NULL);
13396  }
13397 
13398  /* only create the target constraint, if all variables could be copied */
13399  if( *valid )
13400  {
13401  if( name != NULL )
13402  consname = name;
13403  else
13404  consname = SCIPconsGetName(sourcecons);
13405 
13406  /* create a copy of the cumulative constraint */
13407  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13408  sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13409  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13410 
13411  /* adjust left side if the time axis if needed */
13412  if( sourceconsdata->hmin > 0 )
13413  {
13414  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13415  }
13416 
13417  /* adjust right side if the time axis if needed */
13418  if( sourceconsdata->hmax < INT_MAX )
13419  {
13420  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13421  }
13422  }
13423 
13424  /* free buffer array */
13425  SCIPfreeBufferArray(scip, &vars);
13426 
13427  return SCIP_OKAY;
13428 }
13429 
13430 
13431 /** constraint parsing method of constraint handler */
13432 static
13433 SCIP_DECL_CONSPARSE(consParseCumulative)
13434 { /*lint --e{715}*/
13435  SCIP_VAR** vars;
13436  SCIP_VAR* var;
13437  SCIP_Real value;
13438  char strvalue[SCIP_MAXSTRLEN];
13439  char* endptr;
13440  int* demands;
13441  int* durations;
13442  int capacity;
13443  int duration;
13444  int demand;
13445  int hmin;
13446  int hmax;
13447  int varssize;
13448  int nvars;
13449 
13450  SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13451 
13452  /* cutoff "cumulative" form the constraint string */
13453  SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13454  str = endptr;
13455 
13456  varssize = 100;
13457  nvars = 0;
13458 
13459  /* allocate buffer array for variables */
13460  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13461  SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13462  SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13463 
13464  do
13465  {
13466  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13467 
13468  if( var != NULL )
13469  {
13470  str = endptr;
13471 
13472  SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13473  duration = atoi(strvalue);
13474  str = endptr;
13475 
13476  SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13477  demand = atoi(strvalue);
13478  str = endptr;
13479 
13480  SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13481 
13482  vars[nvars] = var;
13483  demands[nvars] = demand;
13484  durations[nvars] = duration;
13485  nvars++;
13486  }
13487  }
13488  while( var != NULL );
13489 
13490  /* parse effective time window */
13491  SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13492  hmin = atoi(strvalue);
13493  str = endptr;
13494 
13495  if( SCIPstrToRealValue(str, &value, &endptr) )
13496  {
13497  hmax = (int)(value);
13498  str = endptr;
13499 
13500  /* parse capacity */
13501  SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13502  str = endptr;
13503  if( SCIPstrToRealValue(str, &value, &endptr) )
13504  {
13505  capacity = (int)value;
13506 
13507  /* create cumulative constraint */
13508  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13509  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13510 
13511  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13512  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13513 
13514  (*success) = TRUE;
13515  }
13516  }
13517 
13518  /* free buffer arrays */
13519  SCIPfreeBufferArray(scip, &durations);
13520  SCIPfreeBufferArray(scip, &demands);
13521  SCIPfreeBufferArray(scip, &vars);
13522 
13523  return SCIP_OKAY;
13524 }
13525 
13526 /** constraint method of constraint handler which returns the variables (if possible) */
13527 static
13528 SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13529 { /*lint --e{715}*/
13530  SCIP_CONSDATA* consdata;
13531 
13532  consdata = SCIPconsGetData(cons);
13533  assert(consdata != NULL);
13534 
13535  if( varssize < consdata->nvars )
13536  (*success) = FALSE;
13537  else
13538  {
13539  assert(vars != NULL);
13540 
13541  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13542  (*success) = TRUE;
13543  }
13544 
13545  return SCIP_OKAY;
13546 }
13547 
13548 /** constraint method of constraint handler which returns the number of variables (if possible) */
13549 static
13550 SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13551 { /*lint --e{715}*/
13552  SCIP_CONSDATA* consdata;
13553 
13554  consdata = SCIPconsGetData(cons);
13555  assert(consdata != NULL);
13556 
13557  (*nvars) = consdata->nvars;
13558  (*success) = TRUE;
13559 
13560  return SCIP_OKAY;
13561 }
13562 
13563 /**@} */
13564 
13565 /**@name Callback methods of event handler
13566  *
13567  * @{
13568  */
13569 
13570 
13571 /** execution method of event handler */
13572 static
13573 SCIP_DECL_EVENTEXEC(eventExecCumulative)
13574 { /*lint --e{715}*/
13575  SCIP_CONSDATA* consdata;
13576 
13577  assert(scip != NULL);
13578  assert(eventhdlr != NULL);
13579  assert(eventdata != NULL);
13580  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13581  assert(event != NULL);
13582 
13583  consdata = (SCIP_CONSDATA*)eventdata;
13584  assert(consdata != NULL);
13585 
13586  /* mark the constraint to be not propagated */
13587  consdata->propagated = FALSE;
13588 
13589  return SCIP_OKAY;
13590 }
13591 
13592 /**@} */
13593 
13594 /**@name Interface methods
13595  *
13596  * @{
13597  */
13598 
13599 /*
13600  * constraint specific interface methods
13601  */
13602 
13603 /** creates the handler for cumulative constraints and includes it in SCIP */
13605  SCIP* scip /**< SCIP data structure */
13606  )
13607 {
13608  SCIP_CONSHDLRDATA* conshdlrdata;
13609  SCIP_CONSHDLR* conshdlr;
13610  SCIP_EVENTHDLR* eventhdlr;
13611 
13612  /* create event handler for bound change events */
13613  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13614 
13615  /* create cumulative constraint handler data */
13616  SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13617 
13618  /* include constraint handler */
13621  consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13622  conshdlrdata) );
13623 
13624  assert(conshdlr != NULL);
13625 
13626  /* set non-fundamental callbacks via specific setter functions */
13627  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13628  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13629 #ifdef SCIP_STATISTIC
13630  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13631 #endif
13632  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13633  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13634  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13635  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13636  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13637  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13638  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13639  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13641  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13642  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropCumulative, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13644  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13645  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13647  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13648  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
13649 
13650  /* add cumulative constraint handler parameters */
13652  "constraints/" CONSHDLR_NAME "/ttinfer",
13653  "should time-table (core-times) propagator be used to infer bounds?",
13654  &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13656  "constraints/" CONSHDLR_NAME "/efcheck",
13657  "should edge-finding be used to detect an overload?",
13658  &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13660  "constraints/" CONSHDLR_NAME "/efinfer",
13661  "should edge-finding be used to infer bounds?",
13662  &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13664  "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13665  &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13667  "constraints/" CONSHDLR_NAME "/ttefcheck",
13668  "should time-table edge-finding be used to detect an overload?",
13669  &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13671  "constraints/" CONSHDLR_NAME "/ttefinfer",
13672  "should time-table edge-finding be used to infer bounds?",
13673  &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13674 
13676  "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13677  &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13679  "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13680  &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13682  "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13683  &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13685  "constraints/" CONSHDLR_NAME "/cutsasconss",
13686  "should the cumulative constraint create cuts as knapsack constraints?",
13687  &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13689  "constraints/" CONSHDLR_NAME "/sepaold",
13690  "shall old sepa algo be applied?",
13691  &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13692 
13694  "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13695  &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13696 
13697  /* presolving parameters */
13699  "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13700  &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13702  "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13703  &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13705  "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13706  &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13708  "constraints/" CONSHDLR_NAME "/presolpairwise",
13709  "should pairwise constraint comparison be performed in presolving?",
13710  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13712  "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13713  &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13714 
13716  "constraints/" CONSHDLR_NAME "/maxnodes",
13717  "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13718  &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13720  "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13721  &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13723  "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13724  &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13725 
13726  /* conflict analysis parameters */
13728  "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13729  &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13730 
13731  return SCIP_OKAY;
13732 }
13733 
13734 /** creates and captures a cumulative constraint */
13736  SCIP* scip, /**< SCIP data structure */
13737  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13738  const char* name, /**< name of constraint */
13739  int nvars, /**< number of variables (jobs) */
13740  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13741  int* durations, /**< array containing corresponding durations */
13742  int* demands, /**< array containing corresponding demands */
13743  int capacity, /**< available cumulative capacity */
13744  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13745  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13746  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13747  * Usually set to TRUE. */
13748  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13749  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13750  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13751  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13752  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13753  * Usually set to TRUE. */
13754  SCIP_Bool local, /**< is constraint only valid locally?
13755  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13756  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13757  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13758  * adds coefficients to this constraint. */
13759  SCIP_Bool dynamic, /**< is constraint subject to aging?
13760  * Usually set to FALSE. Set to TRUE for own cuts which
13761  * are seperated as constraints. */
13762  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13763  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13764  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13765  * if it may be moved to a more global node?
13766  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13767  )
13768 {
13769  SCIP_CONSHDLR* conshdlr;
13770  SCIP_CONSDATA* consdata;
13771 
13772  assert(scip != NULL);
13773 
13774  /* find the cumulative constraint handler */
13775  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13776  if( conshdlr == NULL )
13777  {
13778  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13779  return SCIP_PLUGINNOTFOUND;
13780  }
13781 
13782  SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13783 
13784  /* create constraint data */
13785  SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13786 
13787  /* create constraint */
13788  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13789  initial, separate, enforce, check, propagate,
13790  local, modifiable, dynamic, removable, stickingatnode) );
13791 
13792  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13793  {
13794  SCIP_CONSHDLRDATA* conshdlrdata;
13795 
13796  /* get event handler */
13797  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13798  assert(conshdlrdata != NULL);
13799  assert(conshdlrdata->eventhdlr != NULL);
13800 
13801  /* catch bound change events of variables */
13802  SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13803  }
13804 
13805  return SCIP_OKAY;
13806 }
13807 
13808 /** creates and captures a cumulative constraint
13809  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13810  * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13811  *
13812  * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13813  *
13814  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13815  */
13817  SCIP* scip, /**< SCIP data structure */
13818  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13819  const char* name, /**< name of constraint */
13820  int nvars, /**< number of variables (jobs) */
13821  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13822  int* durations, /**< array containing corresponding durations */
13823  int* demands, /**< array containing corresponding demands */
13824  int capacity /**< available cumulative capacity */
13825  )
13826 {
13827  assert(scip != NULL);
13828 
13829  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13830  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13831 
13832  return SCIP_OKAY;
13833 }
13834 
13835 /** set the left bound of the time axis to be considered (including hmin) */ /*lint -e{715}*/
13837  SCIP* scip, /**< SCIP data structure */
13838  SCIP_CONS* cons, /**< constraint data */
13839  int hmin /**< left bound of time axis to be considered */
13840  )
13841 {
13842  SCIP_CONSDATA* consdata;
13843  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13844  {
13845  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13846  return SCIP_INVALIDCALL;
13847  }
13848 
13849  consdata = SCIPconsGetData(cons);
13850  assert(consdata != NULL);
13851  assert(hmin >= 0);
13852  assert(hmin <= consdata->hmax);
13853 
13854  consdata->hmin = hmin;
13855 
13856  return SCIP_OKAY;
13857 }
13858 
13859 /** returns the left bound of the time axis to be considered */ /*lint -e{715}*/
13861  SCIP* scip, /**< SCIP data structure */
13862  SCIP_CONS* cons /**< constraint */
13863  )
13864 {
13865  SCIP_CONSDATA* consdata;
13866  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13867  {
13868  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13869  SCIPABORT();
13870  return 0; /*lint !e527*/
13871  }
13872 
13873  consdata = SCIPconsGetData(cons);
13874  assert(consdata != NULL);
13875 
13876  return consdata->hmin;
13877 }
13878 
13879 /** set the right bound of the time axis to be considered (not including hmax) */ /*lint -e{715}*/
13881  SCIP* scip, /**< SCIP data structure */
13882  SCIP_CONS* cons, /**< constraint data */
13883  int hmax /**< right bound of time axis to be considered */
13884  )
13885 {
13886  SCIP_CONSDATA* consdata;
13887  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13888  {
13889  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13890  SCIPABORT();
13891  return SCIP_INVALIDCALL; /*lint !e527*/
13892  }
13893 
13894  consdata = SCIPconsGetData(cons);
13895  assert(consdata != NULL);
13896  assert(hmax >= consdata->hmin);
13897 
13898  consdata->hmax = hmax;
13899 
13900  return SCIP_OKAY;
13901 }
13902 
13903 /** returns the right bound of the time axis to be considered */ /*lint -e{715}*/
13905  SCIP* scip, /**< SCIP data structure */
13906  SCIP_CONS* cons /**< constraint */
13907  )
13908 {
13909  SCIP_CONSDATA* consdata;
13910  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13911  {
13912  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13913  SCIPABORT();
13914  return 0; /*lint !e527*/
13915  }
13916 
13917  consdata = SCIPconsGetData(cons);
13918  assert(consdata != NULL);
13919 
13920  return consdata->hmax;
13921 }
13922 
13923 /** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13925  SCIP* scip, /**< SCIP data structure */
13926  SCIP_CONS* cons /**< constraint data */
13927  )
13928 {
13929  SCIP_CONSDATA* consdata;
13930 
13931  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13932  {
13933  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13934  SCIPABORT();
13935  return NULL; /*lint !e527*/
13936  }
13937 
13938  consdata = SCIPconsGetData(cons);
13939  assert(consdata != NULL);
13940 
13941  return consdata->vars;
13942 }
13943 
13944 /** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13946  SCIP* scip, /**< SCIP data structure */
13947  SCIP_CONS* cons /**< constraint data */
13948  )
13949 {
13950  SCIP_CONSDATA* consdata;
13951 
13952  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13953  {
13954  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13955  SCIPABORT();
13956  return -1; /*lint !e527*/
13957  }
13958 
13959  consdata = SCIPconsGetData(cons);
13960  assert(consdata != NULL);
13961 
13962  return consdata->nvars;
13963 }
13964 
13965 /** returns the capacity of the cumulative constraint */ /*lint -e{715}*/
13967  SCIP* scip, /**< SCIP data structure */
13968  SCIP_CONS* cons /**< constraint data */
13969  )
13970 {
13971  SCIP_CONSDATA* consdata;
13972 
13973  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13974  {
13975  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13976  SCIPABORT();
13977  return -1; /*lint !e527*/
13978  }
13979 
13980  consdata = SCIPconsGetData(cons);
13981  assert(consdata != NULL);
13982 
13983  return consdata->capacity;
13984 }
13985 
13986 /** returns the durations of the cumulative constraint */ /*lint -e{715}*/
13988  SCIP* scip, /**< SCIP data structure */
13989  SCIP_CONS* cons /**< constraint data */
13990  )
13991 {
13992  SCIP_CONSDATA* consdata;
13993 
13994  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13995  {
13996  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13997  SCIPABORT();
13998  return NULL; /*lint !e527*/
13999  }
14000 
14001  consdata = SCIPconsGetData(cons);
14002  assert(consdata != NULL);
14003 
14004  return consdata->durations;
14005 }
14006 
14007 /** returns the demands of the cumulative constraint */ /*lint -e{715}*/
14009  SCIP* scip, /**< SCIP data structure */
14010  SCIP_CONS* cons /**< constraint data */
14011  )
14012 {
14013  SCIP_CONSDATA* consdata;
14014 
14015  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14016  {
14017  SCIPerrorMessage("constraint is not a cumulative constraint\n");
14018  SCIPABORT();
14019  return NULL; /*lint !e527*/
14020  }
14021 
14022  consdata = SCIPconsGetData(cons);
14023  assert(consdata != NULL);
14024 
14025  return consdata->demands;
14026 }
14027 
14028 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
14029  * given solution is satisfied
14030  */
14032  SCIP* scip, /**< SCIP data structure */
14033  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
14034  int nvars, /**< number of variables (jobs) */
14035  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14036  int* durations, /**< array containing corresponding durations */
14037  int* demands, /**< array containing corresponding demands */
14038  int capacity, /**< available cumulative capacity */
14039  int hmin, /**< left bound of time axis to be considered (including hmin) */
14040  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14041  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
14042  SCIP_CONS* cons, /**< constraint which is checked */
14043  SCIP_Bool printreason /**< should the reason for the violation be printed? */
14044  )
14045 {
14046  assert(scip != NULL);
14047  assert(violated != NULL);
14048 
14049  SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
14050  violated, cons, printreason) );
14051 
14052  return SCIP_OKAY;
14053 }
14054 
14055 /** normalize cumulative condition */ /*lint -e{715}*/
14057  SCIP* scip, /**< SCIP data structure */
14058  int nvars, /**< number of start time variables (activities) */
14059  SCIP_VAR** vars, /**< array of start time variables */
14060  int* durations, /**< array of durations */
14061  int* demands, /**< array of demands */
14062  int* capacity, /**< pointer to store the changed cumulative capacity */
14063  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
14064  int* nchgsides /**< pointer to count number of side changes */
14065  )
14066 { /*lint --e{715}*/
14067  normalizeCumulativeCondition(scip, nvars, demands, capacity, nchgcoefs, nchgsides);
14068 
14069  return SCIP_OKAY;
14070 }
14071 
14072 /** searches for a time point within the cumulative condition were the cumulative condition can be split */
14074  SCIP* scip, /**< SCIP data structure */
14075  int nvars, /**< number of variables (jobs) */
14076  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14077  int* durations, /**< array containing corresponding durations */
14078  int* demands, /**< array containing corresponding demands */
14079  int capacity, /**< available cumulative capacity */
14080  int* hmin, /**< pointer to store the left bound of the effective horizon */
14081  int* hmax, /**< pointer to store the right bound of the effective horizon */
14082  int* split /**< point were the cumulative condition can be split */
14083  )
14084 {
14085  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14086  hmin, hmax, split) );
14087 
14088  return SCIP_OKAY;
14089 }
14090 
14091 /** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
14093  SCIP* scip, /**< SCIP data structure */
14094  int nvars, /**< number of start time variables (activities) */
14095  SCIP_VAR** vars, /**< array of start time variables */
14096  int* durations, /**< array of durations */
14097  int hmin, /**< left bound of time axis to be considered */
14098  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14099  SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
14100  SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
14101  SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
14102  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
14103  int* nfixedvars, /**< pointer to store the number of fixed variables */
14104  int* nchgsides, /**< pointer to store the number of changed sides */
14105  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
14106  )
14107 {
14108  if( nvars <= 1 )
14109  return SCIP_OKAY;
14110 
14111  /* presolve constraint form the earlier start time point of view */
14112  SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14113  irrelevants, nfixedvars, nchgsides, cutoff) );
14114 
14115  /* presolve constraint form the latest completion time point of view */
14116  SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14117  irrelevants, nfixedvars, nchgsides, cutoff) );
14118 
14119  return SCIP_OKAY;
14120 }
14121 
14122 /** propagate the given cumulative condition */
14124  SCIP* scip, /**< SCIP data structure */
14125  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
14126  int nvars, /**< number of variables (jobs) */
14127  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14128  int* durations, /**< array containing corresponding durations */
14129  int* demands, /**< array containing corresponding demands */
14130  int capacity, /**< available cumulative capacity */
14131  int hmin, /**< left bound of time axis to be considered (including hmin) */
14132  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14133  SCIP_CONS* cons, /**< constraint which gets propagated */
14134  int* nchgbds, /**< pointer to store the number of variable bound changes */
14135  SCIP_Bool* initialized, /**< was conflict analysis initialized */
14136  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14137  SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14138  )
14139 {
14140  SCIP_CONSHDLR* conshdlr;
14141  SCIP_CONSHDLRDATA* conshdlrdata;
14142  SCIP_Bool redundant;
14143 
14144  assert(scip != NULL);
14145  assert(cons != NULL);
14146  assert(initialized != NULL);
14147  assert(*initialized == FALSE);
14148  assert(cutoff != NULL);
14149  assert(*cutoff == FALSE);
14150 
14151  /* find the cumulative constraint handler */
14152  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14153  if( conshdlr == NULL )
14154  {
14155  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14156  return SCIP_PLUGINNOTFOUND;
14157  }
14158 
14159  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14160  assert(conshdlrdata != NULL);
14161 
14162  redundant = FALSE;
14163 
14164  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14165  nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14166  nchgbds, &redundant, initialized, explanation, cutoff) );
14167 
14168  return SCIP_OKAY;
14169 }
14170 
14171 /** resolve propagation w.r.t. the cumulative condition */
14173  SCIP* scip, /**< SCIP data structure */
14174  int nvars, /**< number of start time variables (activities) */
14175  SCIP_VAR** vars, /**< array of start time variables */
14176  int* durations, /**< array of durations */
14177  int* demands, /**< array of demands */
14178  int capacity, /**< cumulative capacity */
14179  int hmin, /**< left bound of time axis to be considered (including hmin) */
14180  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14181  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14182  int inferinfo, /**< the user information */
14183  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14184  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14185  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14186  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14187  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14188  )
14189 {
14190  SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14191  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14192 
14193  return SCIP_OKAY;
14194 }
14195 
14196 /** this method visualizes the cumulative structure in GML format */
14198  SCIP* scip, /**< SCIP data structure */
14199  SCIP_CONS* cons /**< cumulative constraint */
14200  )
14201 {
14202  SCIP_CONSDATA* consdata;
14203  SCIP_HASHTABLE* vars;
14204  FILE* file;
14205  SCIP_VAR* var;
14206  char filename[SCIP_MAXSTRLEN];
14207  int nvars;
14208  int v;
14209 
14210  SCIP_RETCODE retcode = SCIP_OKAY;
14211 
14212  /* open file */
14213  (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14214  file = fopen(filename, "w");
14215 
14216  /* check if the file was open */
14217  if( file == NULL )
14218  {
14219  SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14220  SCIPprintSysError(filename);
14221  return SCIP_FILECREATEERROR;
14222  }
14223 
14224  consdata = SCIPconsGetData(cons);
14225  assert(consdata != NULL);
14226 
14227  nvars = consdata->nvars;
14228 
14229  SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
14230  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
14231 
14232  /* create opening of the GML format */
14233  SCIPgmlWriteOpening(file, TRUE);
14234 
14235  for( v = 0; v < nvars; ++v )
14236  {
14237  char color[SCIP_MAXSTRLEN];
14238 
14239  var = consdata->vars[v];
14240  assert(var != NULL);
14241 
14242  SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
14243 
14244  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14245  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14246  else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14247  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14248  else
14249  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14250 
14251  SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14252  }
14253 
14254  for( v = 0; v < nvars; ++v )
14255  {
14256  SCIP_VAR** vbdvars;
14257  int nvbdvars;
14258  int b;
14259 
14260  var = consdata->vars[v];
14261  assert(var != NULL);
14262 
14263  vbdvars = SCIPvarGetVlbVars(var);
14264  nvbdvars = SCIPvarGetNVlbs(var);
14265 
14266  for( b = 0; b < nvbdvars; ++b )
14267  {
14268  if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14269  {
14270  SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14271  }
14272  }
14273 
14274 #if 0
14275  vbdvars = SCIPvarGetVubVars(var);
14276  nvbdvars = SCIPvarGetNVubs(var);
14277 
14278  for( b = 0; b < nvbdvars; ++b )
14279  {
14280  if( SCIPhashtableExists(vars, vbdvars[b]) )
14281  {
14282  SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14283  }
14284  }
14285 #endif
14286  }
14287 
14288  /* create closing of the GML format */
14289  SCIPgmlWriteClosing(file);
14290 TERMINATE:
14291  /* close file */
14292  fclose(file);
14293 
14294  SCIPhashtableFree(&vars);
14295 
14296  return retcode;
14297 }
14298 
14299 /** sets method to solve an individual cumulative condition */
14301  SCIP* scip, /**< SCIP data structure */
14302  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14303  )
14304 {
14305  SCIP_CONSHDLR* conshdlr;
14306  SCIP_CONSHDLRDATA* conshdlrdata;
14307 
14308  /* find the cumulative constraint handler */
14309  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14310  if( conshdlr == NULL )
14311  {
14312  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14313  return SCIP_PLUGINNOTFOUND;
14314  }
14315 
14316  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14317  assert(conshdlrdata != NULL);
14318 
14319  conshdlrdata->solveCumulative = solveCumulative;
14320 
14321  return SCIP_OKAY;
14322 }
14323 
14324 /** solves given cumulative condition as independent sub problem
14325  *
14326  * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14327  * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14328  * solver was interrupted.
14329  */
14331  SCIP* scip, /**< SCIP data structure */
14332  int njobs, /**< number of jobs (activities) */
14333  SCIP_Real* ests, /**< array with the earlier start time for each job */
14334  SCIP_Real* lsts, /**< array with the latest start time for each job */
14335  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14336  int* durations, /**< array of durations */
14337  int* demands, /**< array of demands */
14338  int capacity, /**< cumulative capacity */
14339  int hmin, /**< left bound of time axis to be considered (including hmin) */
14340  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14341  SCIP_Real timelimit, /**< time limit for solving in seconds */
14342  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14343  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14344  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14345  SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14346  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14347  SCIP_Bool* error /**< pointer to store if an error occurred */
14348  )
14349 {
14350  SCIP_CONSHDLR* conshdlr;
14351  SCIP_CONSHDLRDATA* conshdlrdata;
14352 
14353  (*solved) = TRUE;
14354  (*infeasible) = FALSE;
14355  (*unbounded) = FALSE;
14356  (*error) = FALSE;
14357 
14358  if( njobs == 0 )
14359  return SCIP_OKAY;
14360 
14361  /* find the cumulative constraint handler */
14362  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14363  if( conshdlr == NULL )
14364  {
14365  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14366  (*error) = TRUE;
14367  return SCIP_PLUGINNOTFOUND;
14368  }
14369 
14370  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14371  assert(conshdlrdata != NULL);
14372 
14373  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14374  if( timelimit > 0.0 && memorylimit > 10 )
14375  {
14376  SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14377  hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14378  }
14379 
14380  return SCIP_OKAY;
14381 }
14382 
14383 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14384  * completion time
14385  */
14387  SCIP* scip, /**< SCIP data structure */
14388  SCIP_PROFILE* profile, /**< resource profile */
14389  int nvars, /**< number of variables (jobs) */
14390  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14391  int* durations, /**< array containing corresponding durations */
14392  int* demands /**< array containing corresponding demands */
14393  )
14394 {
14395  SCIP_VAR* var;
14396  SCIP_HASHMAP* addedvars;
14397  int* copydemands;
14398  int* perm;
14399  int duration;
14400  int impliedest;
14401  int est;
14402  int impliedlct;
14403  int lct;
14404  int v;
14405 
14406  /* create hash map for variables which are added, mapping to their duration */
14407  SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
14408 
14409  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14410  SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14411 
14412  /* sort variables w.r.t. job demands */
14413  for( v = 0; v < nvars; ++v )
14414  {
14415  copydemands[v] = demands[v];
14416  perm[v] = v;
14417  }
14418  SCIPsortDownIntInt(copydemands, perm, nvars);
14419 
14420  /* add each job with its earliest start and latest completion time into the resource profile */
14421  for( v = 0; v < nvars; ++v )
14422  {
14423  int idx;
14424 
14425  idx = perm[v];
14426  assert(idx >= 0 && idx < nvars);
14427 
14428  var = vars[idx];
14429  assert(var != NULL);
14430 
14431  duration = durations[idx];
14432  assert(duration > 0);
14433 
14434  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
14435  SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14436 
14437  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14438  SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14439 
14440  if( impliedest < impliedlct )
14441  {
14442  SCIP_Bool infeasible;
14443  int pos;
14444 
14445  SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14446  assert(!infeasible);
14447  assert(pos == -1);
14448  }
14449 
14450  if( est == impliedest && lct == impliedlct )
14451  {
14452  SCIP_CALL( SCIPhashmapInsertInt(addedvars, (void*)var, duration) );
14453  }
14454  }
14455 
14456  SCIPfreeBufferArray(scip, &copydemands);
14457  SCIPfreeBufferArray(scip, &perm);
14458 
14459  SCIPhashmapFree(&addedvars);
14460 
14461  return SCIP_OKAY;
14462 }
14463 
14464 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */ /*lint -e{715}*/
14465 int SCIPcomputeHmin(
14466  SCIP* scip, /**< SCIP data structure */
14467  SCIP_PROFILE* profile, /**< worst case resource profile */
14468  int capacity /**< capacity to check */
14469  )
14470 {
14471  int* timepoints;
14472  int* loads;
14473  int ntimepoints;
14474  int t;
14475 
14476  ntimepoints = SCIPprofileGetNTimepoints(profile);
14477  timepoints = SCIPprofileGetTimepoints(profile);
14478  loads = SCIPprofileGetLoads(profile);
14479 
14480  /* find first time point which potentially violates the capacity restriction */
14481  for( t = 0; t < ntimepoints - 1; ++t )
14482  {
14483  /* check if the time point exceed w.r.t. worst case profile the capacity */
14484  if( loads[t] > capacity )
14485  {
14486  assert(t == 0 || loads[t-1] <= capacity);
14487  return timepoints[t];
14488  }
14489  }
14490 
14491  return INT_MAX;
14492 }
14493 
14494 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity is satisfied for sure */ /*lint -e{715}*/
14495 int SCIPcomputeHmax(
14496  SCIP* scip, /**< SCIP data structure */
14497  SCIP_PROFILE* profile, /**< worst case profile */
14498  int capacity /**< capacity to check */
14499  )
14500 {
14501  int* timepoints;
14502  int* loads;
14503  int ntimepoints;
14504  int t;
14505 
14506  ntimepoints = SCIPprofileGetNTimepoints(profile);
14507  timepoints = SCIPprofileGetTimepoints(profile);
14508  loads = SCIPprofileGetLoads(profile);
14509 
14510  /* find last time point which potentially violates the capacity restriction */
14511  for( t = ntimepoints - 1; t >= 0; --t )
14512  {
14513  /* check if at time point t the worst case resource profile exceeds the capacity */
14514  if( loads[t] > capacity )
14515  {
14516  assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14517  return timepoints[t+1];
14518  }
14519  }
14520 
14521  return INT_MIN;
14522 }
14523 
14524 /**@} */
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
static SCIP_RETCODE consdataCatchEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
#define CONSHDLR_SEPAPRIORITY
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4197
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:86
SCIP_RETCODE SCIPcreateConsBasicSetpart(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
Definition: cons_setppc.c:9096
SCIP_BTNODE * SCIPbtnodeGetRightchild(SCIP_BTNODE *node)
Definition: misc.c:8717
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_EXPORT SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17159
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
static SCIP_DECL_CONSCOPY(consCopyCumulative)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:687
enum TCLIQUE_Status TCLIQUE_STATUS
Definition: tclique.h:59
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:586
static TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
#define DEFAULT_TTINFER
#define CONSHDLR_PROPFREQ
static int computeEnergyContribution(SCIP_BTNODE *node)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:80
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2487
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip_branch.c:656
static SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:877
static SCIP_RETCODE consdataDropAllEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static PROPRULE inferInfoGetProprule(INFERINFO inferinfo)
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:1989
static SCIP_RETCODE checkCumulativeCondition(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *violated, SCIP_CONS *cons, SCIP_Bool printreason)
constraint handler for cumulative constraints
static SCIP_RETCODE propagateEdgeFinding(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:453
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5177
static SCIP_RETCODE computeMinDistance(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int source, int sink, int *naddconss)
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:934
SCIP_RETCODE SCIPaddVarVlb(SCIP *scip, SCIP_VAR *var, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconstant, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip_var.c:6635
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8316
struct TCLIQUE_Graph TCLIQUE_GRAPH
Definition: tclique.h:40
static INFERINFO intToInferInfo(int i)
SCIP_EXPORT int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3250
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:308
SCIP_BTNODE * SCIPbtnodeGetLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8707
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:467
int SCIPprofileGetLoad(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6761
static void consdataPrint(SCIP *scip, SCIP_CONSDATA *consdata, FILE *file)
static SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
static SCIP_RETCODE analyzeConflictOverload(SCIP *scip, SCIP_BTNODE **leaves, int capacity, int nleaves, int est, int lct, int reportedenergy, SCIP_Bool propest, int shift, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation)
static SCIP_RETCODE createCoverCutsTimepoint(SCIP *scip, SCIP_CONS *cons, int *startvalues, int time)
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8276
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:166
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4256
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2599
static void addEndingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *endtimes, int *endindices, int *freecapacity, int *idx, int nvars)
#define SCIP_MAXSTRLEN
Definition: def.h:279
#define DEFAULT_MAXNODES
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:1477
SCIP_RETCODE SCIPcreateConsBasicCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity)
SCIP_RETCODE SCIPnormalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
int SCIPgetHminCumulative(SCIP *scip, SCIP_CONS *cons)
static int computeOverlap(int begin, int end, int est, int lst, int duration)
static SCIP_RETCODE constraintNonOverlappingGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:816
static void normalizeCumulativeCondition(SCIP *scip, int nvars, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
static long bound
SCIP_EXPORT void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
static SCIP_RETCODE analyzeEnergyRequirement(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int begin, int end, SCIP_VAR *infervar, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation)
static void initializeLocks(SCIP_CONSDATA *consdata, SCIP_Bool locked)
#define CONSHDLR_NAME
#define SCIP_CALL_FINALLY(x, y)
Definition: def.h:412
SCIP_VAR ** SCIPgetVarsCumulative(SCIP *scip, SCIP_CONS *cons)
#define CONSHDLR_PROP_TIMING
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1353
SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_setppc.c:9227
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5294
static SCIP_RETCODE createDisjuctiveCons(SCIP *scip, SCIP_CONS *cons, int *naddconss)
#define CONSHDLR_CHECKPRIORITY
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2152
static int inferInfoGetData1(INFERINFO inferinfo)
static SCIP_RETCODE solveIndependentCons(SCIP *scip, SCIP_CONS *cons, SCIP_Longint maxnodes, int *nchgbds, int *nfixedvars, int *ndelconss, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
static void updateKeyOnTrace(SCIP_BTNODE *node, SCIP_Real key)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:9022
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:770
static SCIP_RETCODE presolveConsEst(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
SCIP_Bool SCIPbtnodeIsLeaf(SCIP_BTNODE *node)
Definition: misc.c:8757
static SCIP_RETCODE computePeak(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *timepoint)
SCIP_BTNODE * SCIPbtnodeGetParent(SCIP_BTNODE *node)
Definition: misc.c:8697
static SCIP_Longint computeCoreWithInterval(int begin, int end, int ect, int lst)
static void transitiveClosure(SCIP_Bool **adjmatrix, int *ninarcs, int *noutarcs, int nnodes)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5589
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition: scip_var.c:185
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3132
SCIP_RETCODE SCIPbtCreate(SCIP_BT **tree, BMS_BLKMEM *blkmem)
Definition: misc.c:8859
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:315
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3036
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1986
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8138
static SCIP_RETCODE applyAlternativeBoundsFixing(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, int *nfixedvars, SCIP_Bool *cutoff)
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:360
static SCIP_DECL_SORTPTRCOMP(compNodeEst)
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1368
#define FALSE
Definition: def.h:73
void SCIPstrCopySection(const char *str, char startchar, char endchar, char *token, int size, char **endptr)
Definition: misc.c:10735
static SCIP_RETCODE collectIntVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***activevars, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower, int *lhs)
static SCIP_RETCODE fixIntegerVariableLb(SCIP *scip, SCIP_VAR *var, SCIP_Bool downlock, int *nfixedvars)
SCIP_EXPORT SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17515
static SCIP_RETCODE consdataFreeRows(SCIP *scip, SCIP_CONSDATA **consdata)
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_RETCODE checkOverloadViaThetaTree(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool propest, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPcreateConsLinking(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *linkvar, SCIP_VAR **binvars, SCIP_Real *vals, int nbinvars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_EXPORT SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17182
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:72
#define SCIPdebug(x)
Definition: pub_message.h:84
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
static SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
enum Proprule PROPRULE
static void subtractStartingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *starttimes, int *startindices, int *freecapacity, int *idx, int nvars)
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3468
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:524
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8246
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
static SCIP_RETCODE presolveConsEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff)
static SCIP_RETCODE removeIrrelevantJobs(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE applyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_Real leftub, SCIP_Real rightlb, SCIP_Real *leftimpllbs, SCIP_Real *leftimplubs, SCIP_Real *leftproplbs, SCIP_Real *leftpropubs, SCIP_Real *rightimpllbs, SCIP_Real *rightimplubs, SCIP_Real *rightproplbs, SCIP_Real *rightpropubs, int *nfixedvars, SCIP_Bool *success, SCIP_Bool *cutoff)
static SCIP_RETCODE presolveCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nfixedvars, int *nchgbds, int *ndelconss, int *naddconss, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
static SCIP_RETCODE strengthenVarbounds(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *naddconss)
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:563
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2555
static SCIP_RETCODE getNodeIdx(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_VAR *var, int *idx)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3201
SCIP_EXPORT SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17340
static void conshdlrdataFree(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata)
#define DEFAULT_LOCALCUTS
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:48
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:95
SCIP_Longint SCIPgetMemUsed(SCIP *scip)
Definition: scip_mem.c:91
static SCIP_RETCODE deleteLambdaLeaf(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
#define SCIPdebugMessage
Definition: pub_message.h:87
#define CONSHDLR_DELAYPROP
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1604
static SCIP_RETCODE separateCoverCutsCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
#define DEFAULT_USEBINVARS
SCIP_EXPORT SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17136
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip_cons.c:1233
SCIP_RETCODE SCIPsetSubscipsOff(SCIP *scip, SCIP_Bool quiet)
Definition: scip_param.c:899
static TCLIQUE_ISEDGE(tcliqueIsedgeClique)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:119
tclique user interface
static SCIP_RETCODE createCoreProfile(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
#define DEFAULT_COEFTIGHTENING
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:525
static void normalizeDemands(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
#define SCIP_LONGINT_MAX
Definition: def.h:149
SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:123
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:136
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip_cons.c:1258
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:839
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:78
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:93
#define DEFAULT_TTEFCHECK
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
static void createSelectedSortedEventpointsSol(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *starttimes, int *endtimes, int *startindices, int *endindices, int *nvars, SCIP_Bool lower)
static SCIP_DECL_CONSINITLP(consInitlpCumulative)
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:501
SCIP_RETCODE SCIPsetHmaxCumulative(SCIP *scip, SCIP_CONS *cons, int hmax)
static SCIP_RETCODE propagateAllConss(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *nfixedvars, SCIP_Bool *cutoff, SCIP_Bool *branched)
#define SCIPdebugMsg
Definition: scip_message.h:69
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2107
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
void SCIPprofilePrint(SCIP_PROFILE *profile, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: misc.c:6687
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4347
SCIP_EXPORT void SCIPsortInt(int *intarray, int len)
static SCIP_DECL_CONSPRESOL(consPresolCumulative)
SCIP_EXPORT SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:17871
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:559
#define DEFAULT_NORMALIZE
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
static SCIP_RETCODE deleteTrivilCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:357
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip_cons.c:1461
static SCIP_RETCODE respropCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, INFERINFO inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation, SCIP_RESULT *result)
static SCIP_RETCODE removeOversizedJobs(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *nchgcoefs, int *naddconss, SCIP_Bool *cutoff)
void * SCIPbtnodeGetData(SCIP_BTNODE *node)
Definition: misc.c:8687
static SCIP_RETCODE createConsCumulative(SCIP *scip, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
enum Proprule PROPRULE
static SCIP_RETCODE adjustOversizedJobBounds(SCIP *scip, SCIP_CONSDATA *consdata, int pos, int *nchgbds, int *naddconss, SCIP_Bool *cutoff)
SCIP_Bool SCIPbtnodeIsLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8767
void SCIPgmlWriteOpening(FILE *file, SCIP_Bool directed)
Definition: misc.c:673
void SCIPgmlWriteArc(FILE *file, unsigned int source, unsigned int target, const char *label, const char *color)
Definition: misc.c:629
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:2236
static SCIP_Bool isConsIndependently(SCIP_CONS *cons)
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:265
static SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
static SCIP_RETCODE coretimesUpdateUb(SCIP *scip, SCIP_VAR *var, int duration, int demand, int capacity, SCIP_CONS *cons, SCIP_PROFILE *profile, int idx, int *nchgbds)
SCIP_RETCODE SCIPcreateConsVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static void freeTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
#define CONSHDLR_DESC
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2837
static void createSortedEventpointsSol(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices)
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17387
int SCIPgetNVarsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE conshdlrdataCreate(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition: scip_param.c:619
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3221
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip_copy.c:697
SCIP_RETCODE SCIPsplitCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
static SCIP_RETCODE enforceSolution(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool branch, SCIP_RESULT *result)
SCIP_EXPORT SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:17218
static SCIP_RETCODE separateConsBinaryRepresentation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
static SCIP_RETCODE findPrecedenceConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
static SCIP_DECL_CONSCHECK(consCheckCumulative)
static SCIP_Longint computeTotalEnergy(int *durations, int *demands, int njobs)
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3363
static SCIP_RETCODE tightenLbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int ect, int lct, int begin, int end, SCIP_Longint energy, int *bestlb, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_RETCODE getHighestCapacityUsage(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, int *bestcapacity)
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:92
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8643
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_VAR **vars, SCIP_CONS **linkingconss, int *durations, int *demands, int nvars, int capacity, int hmin, int hmax, SCIP_Bool check)
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip_general.c:283
int SCIPprofileGetNTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6719
Constraint handler for knapsack constraints of the form , x binary and .
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10912
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1581
static const NodeData nodedata[]
Definition: gastrans.c:74
int SCIPcomputeHmin(SCIP *scip, SCIP_PROFILE *profile, int capacity)
#define CONSHDLR_EAGERFREQ
#define CONSHDLR_PRESOLTIMING
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
SCIP_EXPORT const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17017
static SCIP_RETCODE collectBranchingCands(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nbranchcands)
#define CONSHDLR_DELAYSEPA
static SCIP_RETCODE findCumulativeConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
static int inferInfoGetData2(INFERINFO inferinfo)
#define EVENTHDLR_NAME
static SCIP_RETCODE propagateTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_DECL_CONSLOCK(consLockCumulative)
SCIP_RETCODE SCIPapplyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_BOUNDTYPE boundtype, SCIP_Real bound, int maxproprounds, SCIP_Real *impllbs, SCIP_Real *implubs, SCIP_Real *proplbs, SCIP_Real *propubs, SCIP_Bool *cutoff)
SCIP_CONS * SCIPgetConsLinking(SCIP *scip, SCIP_VAR *linkvar)
#define SCIPerrorMessage
Definition: pub_message.h:55
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10705
static SCIP_RETCODE projectVbd(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph)
static SCIP_RETCODE createTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
SCIP_RETCODE SCIPsolveCumulative(SCIP *scip, int njobs, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Real *objvals, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Longint maxnodes, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *error)
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1508
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE collectBinaryVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***vars, int **coefs, int *nvars, int *startindices, int curtime, int nstarted, int nfinished)
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1941
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:109
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
int SCIPgetHmaxCumulative(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:124
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:48
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
static void traceLambdaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
SCIP_EXPORT SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:17923
SCIP_EXPORT void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
static SCIP_RETCODE computeEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss, int *nchgsides)
static int computeEstOmegaset(SCIP *scip, int duration, int demand, int capacity, int est, int lct, int energy)
void SCIPbtnodeFree(SCIP_BT *tree, SCIP_BTNODE **node)
Definition: misc.c:8642
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
static SCIP_RETCODE branch(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_RESULT *result)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:164
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:88
static SCIP_RETCODE propagateCumulativeCondition(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *redundant, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
#define NULL
Definition: lpi_spx1.cpp:155
static TCLIQUE_NEWSOL(tcliqueNewsolClique)
static SCIP_RETCODE coretimesUpdateLb(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_PROFILE *profile, int idx, int *nchgbds, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *infeasible)
static SCIP_RETCODE createCumulativeCons(SCIP *scip, const char *name, TCLIQUE_GRAPH *tcliquegraph, int *cliquenodes, int ncliquenodes)
SCIP_RETCODE SCIPincludeConshdlrCumulative(SCIP *scip)
#define CONSHDLR_MAXPREROUNDS
static SCIP_RETCODE createCoverCuts(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:477
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss, SCIP_Bool *infeasible)
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8107
static SCIP_RETCODE solveCumulative(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool local, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Longint maxnodes, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *error)
#define SCIP_CALL(x)
Definition: def.h:370
SCIP_EXPORT int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:17901
void SCIPswapInts(int *value1, int *value2)
Definition: misc.c:10206
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:632
static SCIP_RETCODE propagateLbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, int *newlbs, int *newubs, int *lbinferinfos, int *ubinferinfos, int *ects, int *flexenergies, int *perm, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static void updateEnvelope(SCIP *scip, SCIP_BTNODE *node)
SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1082
SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
Definition: scip_param.c:677
#define SCIPstatisticPrintf
Definition: pub_message.h:117
static TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
Definition: grphload.c:88
#define DEFAULT_PRESOLPAIRWISE
#define DEFAULT_DETECTDISJUNCTIVE
static SCIP_DECL_CONSFREE(consFreeCumulative)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:56
SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1075
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:114
static SCIP_RETCODE consCapacityConstraintsFinder(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
static void collectDataTTEF(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int hmin, int hmax, int *permests, int *ests, int *permlcts, int *lcts, int *ects, int *lsts, int *flexenergies)
static SCIP_RETCODE consCheckRedundancy(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *redundant)
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1749
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip_param.c:298
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8346
constraint handler for linking binary variables to a linking (continuous or integer) variable ...
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:111
#define SCIP_UNKNOWN
Definition: def.h:184
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:130
SCIP_Real SCIPinfinity(SCIP *scip)
static SCIP_RETCODE propagateUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, int *newlbs, int *newubs, int *lbinferinfos, int *ubinferinfos, int *lsts, int *flexenergies, int *perm, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip_cons.c:220
static void traceThetaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4432
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2286
SCIP_EXPORT void SCIPsortDownIntIntInt(int *intarray1, int *intarray2, int *intarray3, int len)
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:638
#define SCIP_Bool
Definition: def.h:70
static SCIP_RETCODE presolveConsLct(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPincludeDefaultPlugins(SCIP *scip)
static SCIP_RETCODE consdataDropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos)
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:391
static SCIP_DECL_CONSPROP(consPropCumulative)
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1208
#define DEFAULT_DUALPRESOLVE
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3014
SCIP_Bool SCIPbtnodeIsRoot(SCIP_BTNODE *node)
Definition: misc.c:8747
SCIP_EXPORT void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
static SCIP_RETCODE analyseInfeasibelCoreInsertion(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferduration, int inferdemand, int inferpeak, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation)
#define DEFAULT_USEADJUSTEDJOBS
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nchgbds, int *ndelconss, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:332
int SCIPgetNCheckConss(SCIP *scip)
Definition: scip_prob.c:3178
SCIP_EXPORT SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17677
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2473
#define DEFAULT_USECOVERCUTS
SCIP_RETCODE SCIPprofileDeleteCore(SCIP_PROFILE *profile, int left, int right, int demand)
Definition: misc.c:6952
static SCIP_DECL_EVENTEXEC(eventExecCumulative)
int SCIPprofileGetTime(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6749
void SCIPbtSetRoot(SCIP_BT *tree, SCIP_BTNODE *root)
Definition: misc.c:8983
SCIP_Bool SCIPprofileFindLeft(SCIP_PROFILE *profile, int timepoint, int *pos)
Definition: misc.c:6775
#define SCIP_DECL_CONSEXITPRE(x)
Definition: type_cons.h:170
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:91
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4187
#define MAX(x, y)
Definition: tclique_def.h:83
SCIP_RETCODE SCIPsetEmphasis(SCIP *scip, SCIP_PARAMEMPHASIS paramemphasis, SCIP_Bool quiet)
Definition: scip_param.c:877
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip_var.c:105
SCIP_RETCODE SCIPcheckCumulativeCondition(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *violated, SCIP_CONS *cons, SCIP_Bool printreason)
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
void SCIPgmlWriteClosing(FILE *file)
Definition: misc.c:689
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5440
SCIP_Bool SCIPexistsConsLinking(SCIP *scip, SCIP_VAR *linkvar)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8386
SCIP_RETCODE SCIPbtnodeCreate(SCIP_BT *tree, SCIP_BTNODE **node, void *dataptr)
Definition: misc.c:8578
SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
SCIP_Bool SCIPbtIsEmpty(SCIP_BT *tree)
Definition: misc.c:8960
#define SCIP_PRESOLTIMING_ALWAYS
Definition: type_timing.h:49
static SCIP_Bool inferInfoIsValid(INFERINFO inferinfo)
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:126
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8256
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8250
int * SCIPprofileGetLoads(SCIP_PROFILE *profile)
Definition: misc.c:6739
SCIP_BTNODE * SCIPbtGetRoot(SCIP_BT *tree)
Definition: misc.c:8970
int * SCIPgetDurationsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE inferboundsEdgeFinding(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS *cons, SCIP_BT *tree, SCIP_BTNODE **leaves, int capacity, int ncands, SCIP_Bool propest, int shift, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
static SCIP_RETCODE consdataDeletePos(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_CONS *cons, int pos)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1666
#define CONSHDLR_NEEDSCONS
static SCIP_RETCODE computeImpliedEst(SCIP *scip, SCIP_VAR *var, SCIP_HASHMAP *addedvars, int *est)
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8336
static SCIP_RETCODE tightenCoefs(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs)
Proprule
static SCIP_DECL_SORTINDCOMP(compNodedataLct)
SCIP_EXPORT SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17723
#define DEFAULT_FILLBRANCHCANDS
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:95
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:10232
static SCIP_Bool checkDemands(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2125
SCIP_EXPORT int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3193
#define DEFAULT_DETECTVARBOUNDS
static SCIP_RETCODE tightenUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *var, int duration, int demand, int est, int lst, int lct, int begin, int end, SCIP_Longint energy, int *bestub, int *inferinfos, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPrespropCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool *explanation, SCIP_RESULT *result)
static SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
int SCIPconvertRealToInt(SCIP *scip, SCIP_Real real)
static SCIP_RETCODE setupAndSolveCumulativeSubscip(SCIP *subscip, SCIP_Real *objvals, int *durations, int *demands, int njobs, int capacity, int hmin, int hmax, SCIP_Longint maxnodes, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *solved, SCIP_Bool *error)
SCIP_Real * r
Definition: circlepacking.c:50
SCIP_RETCODE SCIPpresolveCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
SCIP_EXPORT SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17733
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip_param.c:561
static void createSortedEventpoints(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices, SCIP_Bool local)
SCIP_VAR ** b
Definition: circlepacking.c:56
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:221
SCIP_RETCODE SCIPsetHminCumulative(SCIP *scip, SCIP_CONS *cons, int hmin)
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5475
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:121
#define CONSHDLR_SEPAFREQ
int SCIPgetCapacityCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE removeRedundantConss(SCIP *scip, SCIP_CONS **conss, int nconss, int *ndelconss)
static SCIP_RETCODE getActiveVar(SCIP *scip, SCIP_VAR **var, int *scalar, int *constant)
static SCIP_RETCODE computeAlternativeBounds(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks)
static void traceLambdaEnergy(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
static SCIP_DECL_CONSPRINT(consPrintCumulative)
static SCIP_RETCODE consdataCollectLinkingCons(SCIP *scip, SCIP_CONSDATA *consdata)
static SCIP_RETCODE initializeDurations(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8266
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnvelop(SCIP_BTNODE *node)
SCIP_RETCODE SCIPtransformConss(SCIP *scip, int nconss, SCIP_CONS **conss, SCIP_CONS **transconss)
Definition: scip_cons.c:1562
int * SCIPprofileGetTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6729
void SCIPbtnodeSetParent(SCIP_BTNODE *node, SCIP_BTNODE *parent)
Definition: misc.c:8820
static SCIP_RETCODE constructIncompatibilityGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
SCIP_EXPORT SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17667
static SCIP_RETCODE moveNodeToLambda(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
SCIP_EXPORT SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:17881
#define DEFAULT_CUTSASCONSS
SCIP_EXPORT void SCIPsortInd(int *indarray, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1641
static void collectThetaSubtree(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
static void collectDemands(SCIP *scip, SCIP_CONSDATA *consdata, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Longint **demands, int *ndemands)
static SCIP_RETCODE separateConsOnIntegerVariables(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool lower, SCIP_Bool *separated, SCIP_Bool *cutoff)
void SCIPbtnodeSetLeftchild(SCIP_BTNODE *node, SCIP_BTNODE *left)
Definition: misc.c:8834
void SCIPprofileFree(SCIP_PROFILE **profile)
Definition: misc.c:6671
SCIP_EXPORT void tcliqueMaxClique(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, TCLIQUE_WEIGHT maxfirstnodeweight, TCLIQUE_WEIGHT minweight, int maxntreenodes, int backtrackfreq, int maxnzeroextensions, int fixednode, int *ntreenodes, TCLIQUE_STATUS *status)
SCIP_EXPORT SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:17891
static SCIP_RETCODE resolvePropagationCoretimes(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferdemand, int inferpeak, int relaxedpeak, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool usebdwidening, int *provedpeak, SCIP_Bool *explanation)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10604
void SCIPbtnodeSetRightchild(SCIP_BTNODE *node, SCIP_BTNODE *right)
Definition: misc.c:8848
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3048
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8077
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1245
SCIP_RETCODE SCIPcreateWorstCaseProfile(SCIP *scip, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands)
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8206
#define SCIPstatistic(x)
Definition: pub_message.h:111
int * SCIPgetDemandsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
#define SCIP_Real
Definition: def.h:163
static SCIP_RETCODE applyAlternativeBoundsBranching(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, SCIP_Bool *branched)
static SCIP_DECL_CONSPARSE(consParseCumulative)
static SCIP_DECL_CONSTRANS(consTransCumulative)
static SCIP_RETCODE propagateTimetable(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
#define SCIP_CALL_TERMINATE(retcode, x, TERM)
Definition: def.h:391
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8097
SCIP_Bool SCIPbtnodeIsRightchild(SCIP_BTNODE *node)
Definition: misc.c:8785
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
static SCIP_RETCODE fixIntegerVariableUb(SCIP *scip, SCIP_VAR *var, SCIP_Bool uplock, int *nfixedvars)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define DEFAULT_EFCHECK
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIP_INVALID
Definition: def.h:183
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1950
static SCIP_RETCODE insertThetanode(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node, SCIP_NODEDATA *nodedatas, int *nodedataidx, int *nnodedatas)
#define EVENTHDLR_DESC
#define DEFAULT_TTEFINFER
void SCIPprintSysError(const char *message)
Definition: misc.c:10513
static SCIP_RETCODE createPrecedenceCons(SCIP *scip, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, int distance)
static INFERINFO getInferInfo(PROPRULE proprule, int data1, int data2)
#define SCIP_Longint
Definition: def.h:148
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition: scip_param.c:445
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8356
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4167
static SCIP_RETCODE detectRedundantConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, int *naddconss)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip_var.c:1791
static SCIP_RETCODE varMayRoundUp(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:345
SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPaddLongintParam(SCIP *scip, const char *name, const char *desc, SCIP_Longint *valueptr, SCIP_Bool isadvanced, SCIP_Longint defaultvalue, SCIP_Longint minvalue, SCIP_Longint maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:102
SCIP_EXPORT int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17360
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2764
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:55
SCIP_RETCODE SCIPcreateConsCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static void consdataCalcSignature(SCIP_CONSDATA *consdata)
#define DEFAULT_EFINFER
#define nnodes
Definition: gastrans.c:65
static SCIP_RETCODE createCapacityRestriction(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool cutsasconss)
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:98
SCIP_RETCODE SCIPpropCumulativeCondition(SCIP *scip, SCIP_PRESOLTIMING presoltiming, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
static SCIP_Bool impliesVlbPrecedenceCondition(SCIP *scip, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconst, int duration)
#define DEFAULT_DISJUNCTIVE
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8590
int SCIPcomputeHmax(SCIP *scip, SCIP_PROFILE *profile, int capacity)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:122
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
#define DEFAULT_USEBDWIDENING
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:315
SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
Definition: scip_mem.c:117
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:199
static SCIP_RETCODE tightenCapacity(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
static SCIP_RETCODE computeEffectiveHorizonCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1110
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition: scip_var.c:8375
void SCIPgmlWriteNode(FILE *file, unsigned int id, const char *label, const char *nodetype, const char *fillcolor, const char *bordercolor)
Definition: misc.c:487
int TCLIQUE_WEIGHT
Definition: tclique.h:39
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:356
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:793
static SCIP_DECL_CONSINITPRE(consInitpreCumulative)
static SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
static SCIP_RETCODE computeImpliedLct(SCIP *scip, SCIP_VAR *var, int duration, SCIP_HASHMAP *addedvars, int *lct)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:266
SCIP_EXPORT SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:17228
#define SCIPABORT()
Definition: def.h:342
SCIP_Real * SCIPgetValsLinking(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSDELETE(consDeleteCumulative)
void SCIPbtFree(SCIP_BT **tree)
Definition: misc.c:8878
SCIP_RETCODE SCIPvisualizeConsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPORT SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:17933
default SCIP plugins
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnergy(SCIP_BTNODE *node)
SCIP_RETCODE SCIPprofileInsertCore(SCIP_PROFILE *profile, int left, int right, int demand, int *pos, SCIP_Bool *infeasible)
Definition: misc.c:6922
static SCIP_DECL_CONSSEPALP(consSepalpCumulative)
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2305
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8296
SCIP_EXPORT SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:17913
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *violated, SCIP_Bool printreason)
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3379
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip_param.c:503
SCIP_RETCODE SCIPprofileCreate(SCIP_PROFILE **profile, int capacity)
Definition: misc.c:6657
static SCIP_RETCODE createCapacityRestrictionIntvars(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
Definition: scip_prob.c:170
SCIP_RETCODE SCIPgetBinvarsLinking(SCIP *scip, SCIP_CONS *cons, SCIP_VAR ***binvars, int *nbinvars)
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:609
static int inferInfoToInt(INFERINFO inferinfo)
static void computeCoreEnergyAfter(SCIP_PROFILE *profile, int nvars, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct)
static TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
SCIP_RETCODE SCIPsetSolveCumulative(SCIP *scip, SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)))
SCIP_EXPORT int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:17859
static SCIP_DECL_CONSRESPROP(consRespropCumulative)
SCIP_EXPORT int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17350
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8326
static SCIP_RETCODE varMayRoundDown(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
#define CONSHDLR_ENFOPRIORITY
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip_solve.c:3461
SCIP_EXPORT int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11713
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
static SCIP_Bool impliesVubPrecedenceCondition(SCIP *scip, SCIP_VAR *var, SCIP_Real vubcoef, SCIP_Real vubconst, int duration)
int SCIPgetNRuns(SCIP *scip)
#define DEFAULT_SEPAOLD