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-2024 Zuse Institute Berlin (ZIB) */
7 /* */
8 /* Licensed under the Apache License, Version 2.0 (the "License"); */
9 /* you may not use this file except in compliance with the License. */
10 /* You may obtain a copy of the License at */
11 /* */
12 /* http://www.apache.org/licenses/LICENSE-2.0 */
13 /* */
14 /* Unless required by applicable law or agreed to in writing, software */
15 /* distributed under the License is distributed on an "AS IS" BASIS, */
16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17 /* See the License for the specific language governing permissions and */
18 /* limitations under the License. */
19 /* */
20 /* You should have received a copy of the Apache-2.0 license */
21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22 /* */
23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 
25 /**@file cons_cumulative.c
26  * @ingroup DEFPLUGINS_CONS
27  * @brief constraint handler for cumulative constraints
28  * @author Timo Berthold
29  * @author Stefan Heinz
30  * @author Jens Schulz
31  *
32  * Given:
33  * - 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
34  * their demands \f$d_j\f$.
35  * - an integer resource capacity \f$C\f$
36  *
37  * 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.
38  *
39  * Separation:
40  * - can be done using binary start time model, see Pritskers, Watters and Wolfe
41  * - or by just separating relatively weak cuts on the integer start time variables
42  *
43  * Propagation:
44  * - time tabling, Klein & Scholl (1999)
45  * - Edge-finding from Petr Vilim, adjusted and simplified for dynamic repropagation
46  * (2009)
47  * - energetic reasoning, see Baptiste, Le Pape, Nuijten (2001)
48  *
49  */
50 
51 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
52 
53 #include <assert.h>
54 #include <string.h>
55 
56 #include "tclique/tclique.h"
57 #include "scip/cons_cumulative.h"
58 #include "scip/cons_linking.h"
59 #include "scip/cons_knapsack.h"
60 #include "scip/scipdefplugins.h"
61 
62 /**@name Constraint handler properties
63  *
64  * @{
65  */
66 
67 /* constraint handler properties */
68 #define CONSHDLR_NAME "cumulative"
69 #define CONSHDLR_DESC "cumulative constraint handler"
70 #define CONSHDLR_SEPAPRIORITY 2100000 /**< priority of the constraint handler for separation */
71 #define CONSHDLR_ENFOPRIORITY -2040000 /**< priority of the constraint handler for constraint enforcing */
72 #define CONSHDLR_CHECKPRIORITY -3030000 /**< priority of the constraint handler for checking feasibility */
73 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
74 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
75 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
76  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
77 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
78 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
79 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
80 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
81 
82 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
83 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
84 
85 /**@} */
86 
87 /**@name Default parameter values
88  *
89  * @{
90  */
91 
92 /* default parameter values */
93 
94 /* separation */
95 #define DEFAULT_USEBINVARS FALSE /**< should the binary representation be used? */
96 #define DEFAULT_LOCALCUTS FALSE /**< should cuts be added only locally? */
97 #define DEFAULT_USECOVERCUTS TRUE /**< should covering cuts be added? */
98 #define DEFAULT_CUTSASCONSS TRUE /**< should the cuts be created as knapsack constraints? */
99 #define DEFAULT_SEPAOLD TRUE /**< shall old sepa algo be applied? */
101 /* propagation */
102 #define DEFAULT_TTINFER TRUE /**< should time-table (core-times) propagator be used to infer bounds? */
103 #define DEFAULT_EFCHECK FALSE /**< should edge-finding be used to detect an overload? */
104 #define DEFAULT_EFINFER FALSE /**< should edge-finding be used to infer bounds? */
105 #define DEFAULT_USEADJUSTEDJOBS FALSE /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
106 #define DEFAULT_TTEFCHECK TRUE /**< should time-table edge-finding be used to detect an overload? */
107 #define DEFAULT_TTEFINFER TRUE /**< should time-table edge-finding be used to infer bounds? */
109 /* presolving */
110 #define DEFAULT_DUALPRESOLVE TRUE /**< should dual presolving be applied? */
111 #define DEFAULT_COEFTIGHTENING FALSE /**< should coeffisient tightening be applied? */
112 #define DEFAULT_NORMALIZE TRUE /**< should demands and capacity be normalized? */
113 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
114 #define DEFAULT_DISJUNCTIVE TRUE /**< extract disjunctive constraints? */
115 #define DEFAULT_DETECTDISJUNCTIVE TRUE /**< search for conflict set via maximal cliques to detect disjunctive constraints */
116 #define DEFAULT_DETECTVARBOUNDS TRUE /**< search for conflict set via maximal cliques to detect variable bound constraints */
117 #define DEFAULT_MAXNODES 10000LL /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
119 /* enforcement */
120 #define DEFAULT_FILLBRANCHCANDS FALSE /**< should branching candidates be added to storage? */
122 /* conflict analysis */
123 #define DEFAULT_USEBDWIDENING TRUE /**< should bound widening be used during conflict analysis? */
125 /**@} */
126 
127 /**@name Event handler properties
128  *
129  * @{
130  */
131 
132 #define EVENTHDLR_NAME "cumulative"
133 #define EVENTHDLR_DESC "bound change event handler for cumulative constraints"
135 /**@} */
136 
137 /*
138  * Data structures
139  */
140 
141 /** constraint data for cumulative constraints */
142 struct SCIP_ConsData
143 {
144  SCIP_VAR** vars; /**< array of variable representing the start time of each job */
145  SCIP_Bool* downlocks; /**< array to store if the variable has a down lock */
146  SCIP_Bool* uplocks; /**< array to store if the variable has an uplock */
147  SCIP_CONS** linkingconss; /**< array of linking constraints for the integer variables */
148  SCIP_ROW** demandrows; /**< array of rows of linear relaxation of this problem */
149  SCIP_ROW** scoverrows; /**< array of rows of small cover cuts of this problem */
150  SCIP_ROW** bcoverrows; /**< array of rows of big cover cuts of this problem */
151  int* demands; /**< array containing corresponding demands */
152  int* durations; /**< array containing corresponding durations */
153  SCIP_Real resstrength1; /**< stores the resource strength 1*/
154  SCIP_Real resstrength2; /**< stores the resource strength 2 */
155  SCIP_Real cumfactor1; /**< stroes the cumulativeness of the constraint */
156  SCIP_Real disjfactor1; /**< stores the disjunctiveness of the constraint */
157  SCIP_Real disjfactor2; /**< stores the disjunctiveness of the constraint */
158  SCIP_Real estimatedstrength;
159  int nvars; /**< number of variables */
160  int varssize; /**< size of the arrays */
161  int ndemandrows; /**< number of rows of cumulative constrint for linear relaxation */
162  int demandrowssize; /**< size of array rows of demand rows */
163  int nscoverrows; /**< number of rows of small cover cuts */
164  int scoverrowssize; /**< size of array of small cover cuts */
165  int nbcoverrows; /**< number of rows of big cover cuts */
166  int bcoverrowssize; /**< size of array of big cover cuts */
167  int capacity; /**< available cumulative capacity */
168 
169  int hmin; /**< left bound of time axis to be considered (including hmin) */
170  int hmax; /**< right bound of time axis to be considered (not including hmax) */
171 
172  unsigned int signature; /**< constraint signature which is need for pairwise comparison */
173 
174  unsigned int validsignature:1; /**< is the signature valid */
175  unsigned int normalized:1; /**< is the constraint normalized */
176  unsigned int covercuts:1; /**< cover cuts are created? */
177  unsigned int propagated:1; /**< is constraint propagted */
178  unsigned int varbounds:1; /**< bool to store if variable bound strengthening was already preformed */
179  unsigned int triedsolving:1; /**< bool to store if we tried already to solve that constraint as independent subproblem */
180 
181 #ifdef SCIP_STATISTIC
182  int maxpeak;
183 #endif
184 };
185 
186 /** constraint handler data */
187 struct SCIP_ConshdlrData
188 {
189  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
190 
191  SCIP_Bool usebinvars; /**< should the binary variables be used? */
192  SCIP_Bool cutsasconss; /**< should the cumulative constraint create cuts as knapsack constraints? */
193  SCIP_Bool ttinfer; /**< should time-table (core-times) propagator be used to infer bounds? */
194  SCIP_Bool efcheck; /**< should edge-finding be used to detect an overload? */
195  SCIP_Bool efinfer; /**< should edge-finding be used to infer bounds? */
196  SCIP_Bool useadjustedjobs; /**< should during edge-finding jobs be adusted which run on the border of the effective time horizon? */
197  SCIP_Bool ttefcheck; /**< should time-table edge-finding be used to detect an overload? */
198  SCIP_Bool ttefinfer; /**< should time-table edge-finding be used to infer bounds? */
199  SCIP_Bool localcuts; /**< should cuts be added only locally? */
200  SCIP_Bool usecovercuts; /**< should covering cuts be added? */
201  SCIP_Bool sepaold; /**< shall old sepa algo be applied? */
202 
203  SCIP_Bool fillbranchcands; /**< should branching candidates be added to storage? */
204 
205  SCIP_Bool dualpresolve; /**< should dual presolving be applied? */
206  SCIP_Bool coeftightening; /**< should coeffisient tightening be applied? */
207  SCIP_Bool normalize; /**< should demands and capacity be normalized? */
208  SCIP_Bool disjunctive; /**< extract disjunctive constraints? */
209  SCIP_Bool detectdisjunctive; /**< search for conflict set via maximal cliques to detect disjunctive constraints */
210  SCIP_Bool detectvarbounds; /**< search for conflict set via maximal cliques to detect variable bound constraints */
211  SCIP_Bool usebdwidening; /**< should bound widening be used during conflict analysis? */
212  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
213  SCIP_Bool detectedredundant; /**< was detection of redundant constraints already performed? */
214 
215  SCIP_Longint maxnodes; /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
216 
217  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)); /**< method to use a single cumulative condition */
218 
219  /* statistic values which are collected if SCIP_STATISTIC is defined */
220 #ifdef SCIP_STATISTIC
221  SCIP_Longint nlbtimetable; /**< number of times the lower bound was tightened by the time-table propagator */
222  SCIP_Longint nubtimetable; /**< number of times the upper bound was tightened by the time-table propagator */
223  SCIP_Longint ncutofftimetable; /**< number of times the a cutoff was detected due to time-table propagator */
224  SCIP_Longint nlbedgefinder; /**< number of times the lower bound was tightened by the edge-finder propagator */
225  SCIP_Longint nubedgefinder; /**< number of times the upper bound was tightened by the edge-finder propagator */
226  SCIP_Longint ncutoffedgefinder; /**< number of times the a cutoff was detected due to edge-finder propagator */
227  SCIP_Longint ncutoffoverload; /**< number of times the a cutoff was detected due to overload checking via edge-finding */
228  SCIP_Longint nlbTTEF; /**< number of times the lower bound was tightened by time-table edge-finding */
229  SCIP_Longint nubTTEF; /**< number of times the upper bound was tightened by time-table edge-finding */
230  SCIP_Longint ncutoffoverloadTTEF;/**< number of times the a cutoff was detected due to overload checking via time-table edge-finding */
231 
232  int nirrelevantjobs; /**< number of time a irrelevant/redundant jobs was removed form a constraint */
233  int nalwaysruns; /**< number of time a job removed form a constraint which run completely during the effective horizon */
234  int nremovedlocks; /**< number of times a up or down lock was removed */
235  int ndualfixs; /**< number of times a dual fix was performed by a single constraint */
236  int ndecomps; /**< number of times a constraint was decomposed */
237  int ndualbranchs; /**< number of times a dual branch was discoverd and applicable via probing */
238  int nallconsdualfixs; /**< number of times a dual fix was performed due to knowledge of all cumulative constraints */
239  int naddedvarbounds; /**< number of added variable bounds constraints */
240  int naddeddisjunctives; /**< number of added disjunctive constraints */
241 
242  SCIP_Bool iscopy; /**< Boolean to store if constraint handler is part of a copy */
243 #endif
244 };
245 
246 /**@name Inference Information Methods
247  *
248  * An inference information can be passed with each domain reduction to SCIP. This information is passed back to the
249  * constraint handler if the corresponding bound change has to be explained. It can be used to store information which
250  * help to construct a reason/explanation for a bound change. The inference information is limited to size of integer.
251  *
252  * In case of the cumulative constraint handler we store the used propagation algorithms for that particular bound
253  * change and the earliest start and latest completion time of all jobs in the conflict set.
254  *
255  * @{
256  */
257 
258 /** Propagation rules */
259 enum Proprule
260 {
261  PROPRULE_0_INVALID = 0, /**< invalid inference information */
262  PROPRULE_1_CORETIMES = 1, /**< core-time propagator */
263  PROPRULE_2_EDGEFINDING = 2, /**< edge-finder */
264  PROPRULE_3_TTEF = 3 /**< time-table edeg-finding */
265 };
266 typedef enum Proprule PROPRULE;
268 /** inference information */
269 struct InferInfo
270 {
271  union
272  {
273  /** struct to use the inference information */
274  struct
275  {
276  unsigned int proprule:2; /**< propagation rule that was applied */
277  unsigned int data1:15; /**< data field one */
278  unsigned int data2:15; /**< data field two */
279  } asbits;
280  int asint; /**< inference information as a single int value */
281  } val;
282 };
283 typedef struct InferInfo INFERINFO;
285 /** converts an integer into an inference information */
286 static
287 INFERINFO intToInferInfo(
288  int i /**< integer to convert */
289  )
290 {
291  INFERINFO inferinfo;
292 
293  inferinfo.val.asint = i;
294 
295  return inferinfo;
296 }
297 
298 /** converts an inference information into an int */
299 static
300 int inferInfoToInt(
301  INFERINFO inferinfo /**< inference information to convert */
302  )
303 {
304  return inferinfo.val.asint;
305 }
306 
307 /** returns the propagation rule stored in the inference information */
308 static
310  INFERINFO inferinfo /**< inference information to convert */
311  )
312 {
313  return (PROPRULE) inferinfo.val.asbits.proprule;
314 }
315 
316 /** returns data field one of the inference information */
317 static
319  INFERINFO inferinfo /**< inference information to convert */
320  )
321 {
322  return (int) inferinfo.val.asbits.data1;
323 }
324 
325 /** returns data field two of the inference information */
326 static
328  INFERINFO inferinfo /**< inference information to convert */
329  )
330 {
331  return (int) inferinfo.val.asbits.data2;
332 }
333 
334 /** returns whether the inference information is valid */
335 static
337  INFERINFO inferinfo /**< inference information to convert */
338  )
339 {
340  return (inferinfo.val.asint != 0);
341 }
342 
343 
344 /** constructs an inference information out of a propagation rule, an earliest start and a latest completion time */
345 static
346 INFERINFO getInferInfo(
347  PROPRULE proprule, /**< propagation rule that deduced the value */
348  int data1, /**< data field one */
349  int data2 /**< data field two */
350  )
351 {
352  INFERINFO inferinfo;
353 
354  /* check that the data members are in the range of the available bits */
355  if( proprule == PROPRULE_0_INVALID || data1 < 0 || data1 >= (1<<15) || data2 < 0 || data2 >= (1<<15) )
356  {
357  inferinfo.val.asint = 0;
358  assert(inferInfoGetProprule(inferinfo) == PROPRULE_0_INVALID);
359  assert(inferInfoIsValid(inferinfo) == FALSE);
360  }
361  else
362  {
363  inferinfo.val.asbits.proprule = proprule; /*lint !e641*/
364  inferinfo.val.asbits.data1 = (unsigned int) data1; /*lint !e732*/
365  inferinfo.val.asbits.data2 = (unsigned int) data2; /*lint !e732*/
366  assert(inferInfoIsValid(inferinfo) == TRUE);
367  }
368 
369  return inferinfo;
370 }
371 
372 /**@} */
373 
374 /*
375  * Local methods
376  */
377 
378 /**@name Miscellaneous Methods
379  *
380  * @{
381  */
382 
383 #ifndef NDEBUG
384 
385 /** compute the core of a job which lies in certain interval [begin, end) */
386 static
388  int begin, /**< begin of the interval */
389  int end, /**< end of the interval */
390  int ect, /**< earliest completion time */
391  int lst /**< latest start time */
392  )
393 {
394  int core;
395 
396  core = MAX(0, MIN(end, ect) - MAX(lst, begin));
397 
398  return core;
399 }
400 #else
401 #define computeCoreWithInterval(begin, end, ect, lst) (MAX(0, MIN((end), (ect)) - MAX((lst), (begin))))
402 #endif
403 
404 /** returns the implied earliest start time */ /*lint -e{715}*/
405 static
407  SCIP* scip, /**< SCIP data structure */
408  SCIP_VAR* var, /**< variable for which the implied est should be returned */
409  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
410  int* est /**< pointer to store the implied earliest start time */
411  )
412 { /*lint --e{715}*/
413 #if 0
414  SCIP_VAR** vbdvars;
415  SCIP_VAR* vbdvar;
416  SCIP_Real* vbdcoefs;
417  SCIP_Real* vbdconsts;
418  void* image;
419  int nvbdvars;
420  int v;
421 #endif
422 
423  (*est) = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
424 
425 #if 0
426  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
427 
428  nvbdvars = SCIPvarGetNVlbs(var);
429  vbdvars = SCIPvarGetVlbVars(var);
430  vbdcoefs = SCIPvarGetVlbCoefs(var);
431  vbdconsts = SCIPvarGetVlbConstants(var);
432 
433  for( v = 0; v < nvbdvars; ++v )
434  {
435  vbdvar = vbdvars[v];
436  assert(vbdvar != NULL);
437 
438  image = SCIPhashmapGetImage(addedvars, (void*)vbdvar);
439 
440  if( image != NULL && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
441  {
442  int duration;
443  int vbdconst;
444 
445  duration = (int)(size_t)image;
446  vbdconst = SCIPconvertRealToInt(scip, vbdconsts[v]);
447 
448  SCIPdebugMsg(scip, "check implication <%s>[%g,%g] >= <%s>[%g,%g] + <%g>\n",
450  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
451 
452  if( duration >= vbdconst )
453  {
454  int impliedest;
455 
456  impliedest = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vbdvar)) + duration;
457 
458  if( (*est) < impliedest )
459  {
460  (*est) = impliedest;
461 
462  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
463  }
464  }
465  }
466  }
467 #endif
468 
469  return SCIP_OKAY;
470 }
471 
472 /** returns the implied latest completion time */ /*lint -e{715}*/
473 static
475  SCIP* scip, /**< SCIP data structure */
476  SCIP_VAR* var, /**< variable for which the implied est should be returned */
477  int duration, /**< duration of the given job */
478  SCIP_HASHMAP* addedvars, /**< hash map containig the variable which are already added */
479  int* lct /**< pointer to store the implied latest completion time */
480  )
481 { /*lint --e{715}*/
482 #if 0
483  SCIP_VAR** vbdvars;
484  SCIP_VAR* vbdvar;
485  SCIP_Real* vbdcoefs;
486  SCIP_Real* vbdconsts;
487  int nvbdvars;
488  int v;
489 #endif
490 
491  (*lct) = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
492 
493 #if 0
494  /* the code contains a bug; we need to check if an implication forces that the jobs do not run in parallel */
495 
496  nvbdvars = SCIPvarGetNVubs(var);
497  vbdvars = SCIPvarGetVubVars(var);
498  vbdcoefs = SCIPvarGetVubCoefs(var);
499  vbdconsts = SCIPvarGetVubConstants(var);
500 
501  for( v = 0; v < nvbdvars; ++v )
502  {
503  vbdvar = vbdvars[v];
504  assert(vbdvar != NULL);
505 
506  if( SCIPhashmapExists(addedvars, (void*)vbdvar) && SCIPisEQ(scip, vbdcoefs[v], 1.0 ) )
507  {
508  int vbdconst;
509 
510  vbdconst = SCIPconvertRealToInt(scip, -vbdconsts[v]);
511 
512  SCIPdebugMsg(scip, "check implication <%s>[%g,%g] <= <%s>[%g,%g] + <%g>\n",
514  SCIPvarGetName(vbdvar), SCIPvarGetLbLocal(vbdvar), SCIPvarGetUbLocal(vbdvar), vbdconsts[v]);
515 
516  if( duration >= -vbdconst )
517  {
518  int impliedlct;
519 
520  impliedlct = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vbdvar));
521 
522  if( (*lct) > impliedlct )
523  {
524  (*lct) = impliedlct;
525 
526  SCIP_CALL( SCIPhashmapRemove(addedvars, (void*)vbdvar) );
527  }
528  }
529  }
530  }
531 #endif
532 
533  return SCIP_OKAY;
534 }
535 
536 /** collects all necessary binary variables to represent the jobs which can be active at time point of interest */
537 static
539  SCIP* scip, /**< SCIP data structure */
540  SCIP_CONSDATA* consdata, /**< constraint data */
541  SCIP_VAR*** vars, /**< pointer to the array to store the binary variables */
542  int** coefs, /**< pointer to store the coefficients */
543  int* nvars, /**< number if collect binary variables */
544  int* startindices, /**< permutation with rspect to the start times */
545  int curtime, /**< current point in time */
546  int nstarted, /**< number of jobs that start before the curtime or at curtime */
547  int nfinished /**< number of jobs that finished before curtime or at curtime */
548  )
549 {
550  int nrowvars;
551  int startindex;
552  int size;
553 
554  size = 10;
555  nrowvars = 0;
556  startindex = nstarted - 1;
557 
558  SCIP_CALL( SCIPallocBufferArray(scip, vars, size) );
559  SCIP_CALL( SCIPallocBufferArray(scip, coefs, size) );
560 
561  /* search for the (nstarted - nfinished) jobs which are active at curtime */
562  while( nstarted - nfinished > nrowvars )
563  {
564  SCIP_VAR* var;
565  int endtime;
566  int duration;
567  int demand;
568  int varidx;
569 
570  /* collect job information */
571  varidx = startindices[startindex];
572  assert(varidx >= 0 && varidx < consdata->nvars);
573 
574  var = consdata->vars[varidx];
575  duration = consdata->durations[varidx];
576  demand = consdata->demands[varidx];
577  assert(var != NULL);
578 
579  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
580 
581  /* check the end time of this job is larger than the curtime; in this case the job is still running */
582  if( endtime > curtime )
583  {
584  SCIP_VAR** binvars;
585  SCIP_Real* vals;
586  int nbinvars;
587  int start;
588  int end;
589  int b;
590 
591  /* check if the linking constraints exists */
592  assert(SCIPexistsConsLinking(scip, var));
593  assert(SCIPgetConsLinking(scip, var) != NULL);
594  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[varidx]);
595 
596  /* collect linking constraint information */
597  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[varidx], &binvars, &nbinvars) );
598  vals = SCIPgetValsLinking(scip, consdata->linkingconss[varidx]);
599 
600  start = curtime - duration + 1;
601  end = MIN(curtime, endtime - duration);
602 
603  for( b = 0; b < nbinvars; ++b )
604  {
605  if( vals[b] < start )
606  continue;
607 
608  if( vals[b] > end )
609  break;
610 
611  assert(binvars[b] != NULL);
612 
613  /* ensure array proper array size */
614  if( size == *nvars )
615  {
616  size *= 2;
617  SCIP_CALL( SCIPreallocBufferArray(scip, vars, size) );
618  SCIP_CALL( SCIPreallocBufferArray(scip, coefs, size) );
619  }
620 
621  (*vars)[*nvars] = binvars[b];
622  (*coefs)[*nvars] = demand;
623  (*nvars)++;
624  }
625  nrowvars++;
626  }
627 
628  startindex--;
629  }
630 
631  return SCIP_OKAY;
632 }
633 
634 /** collect all integer variable which belong to jobs which can run at the point of interest */
635 static
637  SCIP* scip, /**< SCIP data structure */
638  SCIP_CONSDATA* consdata, /**< constraint data */
639  SCIP_VAR*** activevars, /**< jobs that are currently running */
640  int* startindices, /**< permutation with rspect to the start times */
641  int curtime, /**< current point in time */
642  int nstarted, /**< number of jobs that start before the curtime or at curtime */
643  int nfinished, /**< number of jobs that finished before curtime or at curtime */
644  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
645  int* lhs /**< lhs for the new row sum of lbs + minoffset */
646  )
647 {
648  SCIP_VAR* var;
649  int startindex;
650  int endtime;
651  int duration;
652  int starttime;
653 
654  int varidx;
655  int sumofstarts;
656  int mindelta;
657  int counter;
658 
659  assert(curtime >= consdata->hmin);
660  assert(curtime < consdata->hmax);
661 
662  counter = 0;
663  sumofstarts = 0;
664 
665  mindelta = INT_MAX;
666 
667  startindex = nstarted - 1;
668 
669  /* search for the (nstarted - nfinished) jobs which are active at curtime */
670  while( nstarted - nfinished > counter )
671  {
672  assert(startindex >= 0);
673 
674  /* collect job information */
675  varidx = startindices[startindex];
676  assert(varidx >= 0 && varidx < consdata->nvars);
677 
678  var = consdata->vars[varidx];
679  duration = consdata->durations[varidx];
680  assert(duration > 0);
681  assert(var != NULL);
682 
683  if( lower )
684  starttime = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
685  else
686  starttime = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
687 
688  endtime = MIN(starttime + duration, consdata->hmax);
689 
690  /* check the end time of this job is larger than the curtime; in this case the job is still running */
691  if( endtime > curtime )
692  {
693  (*activevars)[counter] = var;
694  sumofstarts += starttime;
695  mindelta = MIN(mindelta, endtime - curtime); /* this amount of schifting holds for lb and ub */
696  counter++;
697  }
698 
699  startindex--;
700  }
701 
702  assert(mindelta > 0);
703  *lhs = lower ? sumofstarts + mindelta : sumofstarts - mindelta;
704 
705  return SCIP_OKAY;
706 }
707 
708 /** initialize the sorted event point arrays */
709 static
711  SCIP* scip, /**< SCIP data structure */
712  int nvars, /**< number of start time variables (activities) */
713  SCIP_VAR** vars, /**< array of start time variables */
714  int* durations, /**< array of durations per start time variable */
715  int* starttimes, /**< array to store sorted start events */
716  int* endtimes, /**< array to store sorted end events */
717  int* startindices, /**< permutation with rspect to the start times */
718  int* endindices, /**< permutation with rspect to the end times */
719  SCIP_Bool local /**< shall local bounds be used */
720  )
721 {
722  SCIP_VAR* var;
723  int j;
724 
725  assert(vars != NULL || nvars == 0);
726 
727  /* assign variables, start and endpoints to arrays */
728  for ( j = 0; j < nvars; ++j )
729  {
730  assert(vars != NULL);
731 
732  var = vars[j];
733  assert(var != NULL);
734 
735  if( local )
736  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
737  else
738  starttimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
739 
740  startindices[j] = j;
741 
742  if( local )
743  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + durations[j];
744  else
745  endtimes[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + durations[j];
746 
747  endindices[j] = j;
748  }
749 
750  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
751  SCIPsortIntInt(starttimes, startindices, j);
752  SCIPsortIntInt(endtimes, endindices, j);
753 }
754 
755 /** initialize the sorted event point arrays w.r.t. the given primal solutions */
756 static
758  SCIP* scip, /**< SCIP data structure */
759  SCIP_SOL* sol, /**< solution */
760  int nvars, /**< number of start time variables (activities) */
761  SCIP_VAR** vars, /**< array of start time variables */
762  int* durations, /**< array of durations per start time variable */
763  int* starttimes, /**< array to store sorted start events */
764  int* endtimes, /**< array to store sorted end events */
765  int* startindices, /**< permutation with rspect to the start times */
766  int* endindices /**< permutation with rspect to the end times */
767  )
768 {
769  SCIP_VAR* var;
770  int j;
771 
772  assert(vars != NULL || nvars == 0);
773 
774  /* assign variables, start and endpoints to arrays */
775  for ( j = 0; j < nvars; ++j )
776  {
777  assert(vars != NULL);
778 
779  var = vars[j];
780  assert(var != NULL);
781 
782  starttimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
783  startindices[j] = j;
784 
785  endtimes[j] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var)) + durations[j];
786  endindices[j] = j;
787  }
788 
789  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
790  SCIPsortIntInt(starttimes, startindices, j);
791  SCIPsortIntInt(endtimes, endindices, j);
792 }
793 
794 /** initialize the sorted event point arrays
795  *
796  * @todo Check the separation process!
797  */
798 static
800  SCIP* scip, /**< SCIP data structure */
801  SCIP_CONSDATA* consdata, /**< constraint data */
802  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
803  int* starttimes, /**< array to store sorted start events */
804  int* endtimes, /**< array to store sorted end events */
805  int* startindices, /**< permutation with rspect to the start times */
806  int* endindices, /**< permutation with rspect to the end times */
807  int* nvars, /**< number of variables that are integral */
808  SCIP_Bool lower /**< shall the constraints be derived for lower or upper bounds? */
809  )
810 {
811  SCIP_VAR* var;
812  int tmpnvars;
813  int j;
814 
815  tmpnvars = consdata->nvars;
816  *nvars = 0;
817 
818  /* assign variables, start and endpoints to arrays */
819  for ( j = 0; j < tmpnvars; ++j )
820  {
821  var = consdata->vars[j];
822  assert(var != NULL);
823  assert(consdata->durations[j] > 0);
824  assert(consdata->demands[j] > 0);
825 
826  if( lower )
827  {
828  /* only consider jobs that are at their lower or upper bound */
829  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
830  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var)) )
831  continue;
832 
833  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
834  startindices[*nvars] = j;
835 
836  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
837  endindices[*nvars] = j;
838 
839  SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
840  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
841  consdata->durations[j],
842  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
843  consdata->demands[startindices[*nvars]]);
844 
845  (*nvars)++;
846  }
847  else
848  {
849  if( !SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, var))
850  || !SCIPisFeasEQ(scip, SCIPgetSolVal(scip, sol, var), SCIPvarGetUbLocal(var)) )
851  continue;
852 
853  starttimes[*nvars] = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, var));
854  startindices[*nvars] = j;
855 
856  endtimes[*nvars] = starttimes[*nvars] + consdata->durations[j];
857  endindices[*nvars] = j;
858 
859  SCIPdebugMsg(scip, "%d: variable <%s>[%g,%g] (sol %g, duration %d) starttime %d, endtime = %d, demand = %d\n",
860  *nvars, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPgetSolVal(scip, sol, var),
861  consdata->durations[j],
862  starttimes[*nvars], starttimes[*nvars] + consdata->durations[startindices[*nvars]],
863  consdata->demands[startindices[*nvars]]);
864 
865  (*nvars)++;
866  }
867  }
868 
869  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
870  SCIPsortIntInt(starttimes, startindices, *nvars);
871  SCIPsortIntInt(endtimes, endindices, *nvars);
872 
873 #ifdef SCIP_DEBUG
874  SCIPdebugMsg(scip, "sorted output %d\n", *nvars);
875 
876  for ( j = 0; j < *nvars; ++j )
877  {
878  SCIPdebugMsg(scip, "%d: job[%d] starttime %d, endtime = %d, demand = %d\n", j,
879  startindices[j], starttimes[j], starttimes[j] + consdata->durations[startindices[j]],
880  consdata->demands[startindices[j]]);
881  }
882 
883  for ( j = 0; j < *nvars; ++j )
884  {
885  SCIPdebugMsg(scip, "%d: job[%d] endtime %d, demand = %d\n", j, endindices[j], endtimes[j],
886  consdata->demands[endindices[j]]);
887  }
888 #endif
889 }
890 
891 #ifdef SCIP_STATISTIC
892 /** this method checks for relevant intervals for energetic reasoning */
893 static
894 SCIP_RETCODE computeRelevantEnergyIntervals(
895  SCIP* scip, /**< SCIP data structure */
896  int nvars, /**< number of start time variables (activities) */
897  SCIP_VAR** vars, /**< array of start time variables */
898  int* durations, /**< array of durations */
899  int* demands, /**< array of demands */
900  int capacity, /**< cumulative capacity */
901  int hmin, /**< left bound of time axis to be considered (including hmin) */
902  int hmax, /**< right bound of time axis to be considered (not including hmax) */
903  int** timepoints, /**< array to store relevant points in time */
904  SCIP_Real** cumulativedemands, /**< array to store the estimated cumulative demand for each point in time */
905  int* ntimepoints, /**< pointer to store the number of timepoints */
906  int* maxdemand, /**< pointer to store maximum over all demands */
907  SCIP_Real* minfreecapacity /**< pointer to store the minimum free capacity */
908  )
909 {
910  int* starttimes; /* stores when each job is starting */
911  int* endtimes; /* stores when each job ends */
912  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
913  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
914 
915  SCIP_Real totaldemand;
916  int curtime; /* point in time which we are just checking */
917  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
918 
919  int j;
920 
921  assert( scip != NULL );
922  assert(durations != NULL);
923  assert(demands != NULL);
924  assert(capacity >= 0);
925 
926  /* if no activities are associated with this cumulative then this constraint is redundant */
927  if( nvars == 0 )
928  return SCIP_OKAY;
929 
930  assert(vars != NULL);
931 
932  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
933  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
934  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
935  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
936 
937  /* create event point arrays */
938  createSortedEventpoints(scip, nvars, vars, durations, starttimes, endtimes, startindices, endindices, TRUE);
939 
940  endindex = 0;
941  totaldemand = 0.0;
942 
943  *ntimepoints = 0;
944  (*timepoints)[0] = starttimes[0];
945  (*cumulativedemands)[0] = 0;
946  *maxdemand = 0;
947 
948  /* check each startpoint of a job whether the capacity is kept or not */
949  for( j = 0; j < nvars; ++j )
950  {
951  int lct;
952  int idx;
953 
954  curtime = starttimes[j];
955 
956  if( curtime >= hmax )
957  break;
958 
959  /* free all capacity usages of jobs the are no longer running */
960  while( endindex < nvars && endtimes[endindex] <= curtime )
961  {
962  int est;
963 
964  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
965  {
966  (*ntimepoints)++;
967  (*timepoints)[*ntimepoints] = endtimes[endindex];
968  (*cumulativedemands)[*ntimepoints] = 0;
969  }
970 
971  idx = endindices[endindex];
972  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
973  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
974  endindex++;
975 
976  (*cumulativedemands)[*ntimepoints] = totaldemand;
977  }
978 
979  idx = startindices[j];
980  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
981  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
982 
983  if( (*timepoints)[*ntimepoints] < curtime )
984  {
985  (*ntimepoints)++;
986  (*timepoints)[*ntimepoints] = curtime;
987  (*cumulativedemands)[*ntimepoints] = 0;
988  }
989 
990  (*cumulativedemands)[*ntimepoints] = totaldemand;
991 
992  /* add the relative capacity requirements for all job which start at the curtime */
993  while( j+1 < nvars && starttimes[j+1] == curtime )
994  {
995  ++j;
996  idx = startindices[j];
997  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[idx]) + durations[idx]);
998  totaldemand += (SCIP_Real) demands[idx] * durations[idx] / (lct - starttimes[j]);
999 
1000  (*cumulativedemands)[*ntimepoints] = totaldemand;
1001  }
1002  } /*lint --e{850}*/
1003 
1004  /* free all capacity usages of jobs that are no longer running */
1005  while( endindex < nvars/* && endtimes[endindex] < hmax*/)
1006  {
1007  int est;
1008  int idx;
1009 
1010  if( (*timepoints)[*ntimepoints] < endtimes[endindex] )
1011  {
1012  (*ntimepoints)++;
1013  (*timepoints)[*ntimepoints] = endtimes[endindex];
1014  (*cumulativedemands)[*ntimepoints] = 0;
1015  }
1016 
1017  idx = endindices[endindex];
1018  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[idx]));
1019  totaldemand -= (SCIP_Real) demands[idx] * durations[idx] / (endtimes[endindex] - est);
1020  (*cumulativedemands)[*ntimepoints] = totaldemand;
1021 
1022  ++endindex;
1023  }
1024 
1025  (*ntimepoints)++;
1026  /* compute minimum free capacity */
1027  (*minfreecapacity) = INT_MAX;
1028  for( j = 0; j < *ntimepoints; ++j )
1029  {
1030  if( (*timepoints)[j] >= hmin && (*timepoints)[j] < hmax )
1031  *minfreecapacity = MIN( *minfreecapacity, (SCIP_Real)capacity - (*cumulativedemands)[j] );
1032  }
1033 
1034  /* free buffer arrays */
1035  SCIPfreeBufferArray(scip, &endindices);
1036  SCIPfreeBufferArray(scip, &startindices);
1037  SCIPfreeBufferArray(scip, &endtimes);
1038  SCIPfreeBufferArray(scip, &starttimes);
1039 
1040  return SCIP_OKAY;
1041 }
1042 
1043 /** evaluates the cumulativeness and disjointness factor of a cumulative constraint */
1044 static
1045 SCIP_RETCODE evaluateCumulativeness(
1046  SCIP* scip, /**< pointer to scip */
1047  SCIP_CONS* cons /**< cumulative constraint */
1048  )
1049 {
1050  SCIP_CONSDATA* consdata;
1051  int nvars;
1052  int v;
1053  int capacity;
1054 
1055  /* output values: */
1056  SCIP_Real disjfactor2; /* (peak-capacity)/capacity * (large demands/nvars_t) */
1057  SCIP_Real cumfactor1;
1058  SCIP_Real resstrength1; /* overall strength */
1059  SCIP_Real resstrength2; /* timepoint wise maximum */
1060 
1061  /* helpful variables: */
1062  SCIP_Real globalpeak;
1063  SCIP_Real globalmaxdemand;
1064 
1065  /* get constraint data structure */
1066  consdata = SCIPconsGetData(cons);
1067  assert(consdata != NULL);
1068 
1069  nvars = consdata->nvars;
1070  capacity = consdata->capacity;
1071  globalpeak = 0.0;
1072  globalmaxdemand = 0.0;
1073 
1074  disjfactor2 = 0.0;
1075  cumfactor1 = 0.0;
1076  resstrength2 = 0.0;
1077 
1078  /* check each starting time (==each job, but inefficient) */
1079  for( v = 0; v < nvars; ++v )
1080  {
1081  SCIP_Real peak;
1082  SCIP_Real maxdemand;
1083  SCIP_Real deltademand;
1084  int ndemands;
1085  int nlarge;
1086 
1087  int timepoint;
1088  int j;
1089  timepoint = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[v]));
1090  peak = consdata->demands[v];
1091  ndemands = 1;
1092  maxdemand = 0;
1093  nlarge = 0;
1094 
1095  if( consdata->demands[v] > capacity / 3 )
1096  nlarge++;
1097 
1098  for( j = 0; j < nvars; ++j )
1099  {
1100  int lb;
1101 
1102  if( j == v )
1103  continue;
1104 
1105  maxdemand = 0.0;
1106  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
1107 
1108  if( lb <= timepoint && lb + consdata->durations[j] > timepoint )
1109  {
1110  peak += consdata->demands[j];
1111  ndemands++;
1112 
1113  if( consdata->demands[j] > consdata->capacity / 3 )
1114  nlarge++;
1115  }
1116  }
1117 
1118  deltademand = (SCIP_Real)peak / (SCIP_Real)ndemands;
1119  globalpeak = MAX(globalpeak, peak);
1120  globalmaxdemand = MAX(globalmaxdemand, maxdemand);
1121 
1122  if( peak > capacity )
1123  {
1124  disjfactor2 = MAX( disjfactor2, (peak-(SCIP_Real)capacity)/peak * (nlarge/(SCIP_Real)ndemands) );
1125  cumfactor1 = MAX( cumfactor1, (peak-capacity)/peak * (capacity-deltademand)/(SCIP_Real)capacity );
1126  resstrength2 = MAX(resstrength2, (capacity-maxdemand)/(peak-maxdemand) );
1127  }
1128  }
1129 
1130  resstrength1 = (capacity-globalmaxdemand) / (globalpeak-globalmaxdemand);
1131 
1132  consdata->maxpeak = SCIPconvertRealToInt(scip, globalpeak);
1133  consdata->disjfactor2 = disjfactor2;
1134  consdata->cumfactor1 = cumfactor1;
1135  consdata->resstrength2 = resstrength2;
1136  consdata->resstrength1 = resstrength1;
1137 
1138  /* get estimated res strength */
1139  {
1140  int* timepoints;
1141  SCIP_Real* estimateddemands;
1142  int ntimepoints;
1143  int maxdemand;
1144  SCIP_Real minfreecapacity;
1145 
1146  SCIP_CALL( SCIPallocBufferArray(scip, &timepoints, 2*nvars) );
1147  SCIP_CALL( SCIPallocBufferArray(scip, &estimateddemands, 2*nvars) );
1148 
1149  ntimepoints = 0;
1150  minfreecapacity = INT_MAX;
1151 
1152  SCIP_CALL( computeRelevantEnergyIntervals(scip, nvars, consdata->vars,
1153  consdata->durations, consdata->demands,
1154  capacity, consdata->hmin, consdata->hmax, &timepoints, &estimateddemands,
1155  &ntimepoints, &maxdemand, &minfreecapacity) );
1156 
1157  /* free buffer arrays */
1158  SCIPfreeBufferArray(scip, &estimateddemands);
1159  SCIPfreeBufferArray(scip, &timepoints);
1160 
1161  consdata->estimatedstrength = (SCIP_Real)(capacity - minfreecapacity) / (SCIP_Real) capacity;
1162  }
1163 
1164  SCIPstatisticPrintf("cumulative constraint<%s>: DISJ1=%g, DISJ2=%g, CUM=%g, RS1 = %g, RS2 = %g, EST = %g\n",
1165  SCIPconsGetName(cons), consdata->disjfactor1, disjfactor2, cumfactor1, resstrength1, resstrength2,
1166  consdata->estimatedstrength);
1167 
1168  return SCIP_OKAY;
1169 }
1170 #endif
1171 
1172 /** gets the active variables together with the constant */
1173 static
1175  SCIP* scip, /**< SCIP data structure */
1176  SCIP_VAR** var, /**< pointer to store the active variable */
1177  int* scalar, /**< pointer to store the scalar */
1178  int* constant /**< pointer to store the constant */
1179  )
1180 {
1181  if( !SCIPvarIsActive(*var) )
1182  {
1183  SCIP_Real realscalar;
1184  SCIP_Real realconstant;
1185 
1186  realscalar = 1.0;
1187  realconstant = 0.0;
1188 
1190 
1191  /* transform variable to active variable */
1192  SCIP_CALL( SCIPgetProbvarSum(scip, var, &realscalar, &realconstant) );
1193  assert(!SCIPisZero(scip, realscalar));
1194  assert(SCIPvarIsActive(*var));
1195 
1196  if( realconstant < 0.0 )
1197  (*constant) = -SCIPconvertRealToInt(scip, -realconstant);
1198  else
1199  (*constant) = SCIPconvertRealToInt(scip, realconstant);
1200 
1201  if( realscalar < 0.0 )
1202  (*scalar) = -SCIPconvertRealToInt(scip, -realscalar);
1203  else
1204  (*scalar) = SCIPconvertRealToInt(scip, realscalar);
1205  }
1206  else
1207  {
1208  (*scalar) = 1;
1209  (*constant) = 0;
1210  }
1211 
1212  assert(*scalar != 0);
1213 
1214  return SCIP_OKAY;
1215 }
1216 
1217 /** computes the total energy of all jobs */
1218 static
1220  int* durations, /**< array of job durations */
1221  int* demands, /**< array of job demands */
1222  int njobs /**< number of jobs */
1223  )
1224 {
1225  SCIP_Longint energy;
1226  int j;
1227 
1228  energy = 0;
1229 
1230  for( j = 0; j < njobs; ++j )
1231  energy += (SCIP_Longint) durations[j] * demands[j];
1232 
1233  return energy;
1234 }
1235 
1236 /**@} */
1237 
1238 /**@name Default method to solve a cumulative condition
1239  *
1240  * @{
1241  */
1242 
1243 /** setup and solve subscip to solve single cumulative condition */
1244 static
1246  SCIP* subscip, /**< subscip data structure */
1247  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
1248  int* durations, /**< array of durations */
1249  int* demands, /**< array of demands */
1250  int njobs, /**< number of jobs (activities) */
1251  int capacity, /**< cumulative capacity */
1252  int hmin, /**< left bound of time axis to be considered (including hmin) */
1253  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1254  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes (-1: no limit) */
1255  SCIP_Real timelimit, /**< time limit for solving in seconds */
1256  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
1257  SCIP_Real* ests, /**< array of earliest start times for each job */
1258  SCIP_Real* lsts, /**< array of latest start times for each job */
1259  SCIP_Bool* infeasible, /**< pointer to store if the subproblem was infeasible */
1260  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
1261  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
1262  SCIP_Bool* error /**< pointer to store if an error occurred */
1263  )
1264 {
1265  SCIP_VAR** subvars;
1266  SCIP_CONS* cons;
1267 
1268  char name[SCIP_MAXSTRLEN];
1269  int v;
1270  SCIP_RETCODE retcode;
1271 
1272  assert(subscip != NULL);
1273 
1274  /* copy all plugins */
1276 
1277  /* create the subproblem */
1278  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1279 
1280  SCIP_CALL( SCIPallocBlockMemoryArray(subscip, &subvars, njobs) );
1281 
1282  /* create for each job a start time variable */
1283  for( v = 0; v < njobs; ++v )
1284  {
1285  SCIP_Real objval;
1286 
1287  /* construct variable name */
1288  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job%d", v);
1289 
1290  if( objvals == NULL )
1291  objval = 0.0;
1292  else
1293  objval = objvals[v];
1294 
1295  SCIP_CALL( SCIPcreateVarBasic(subscip, &subvars[v], name, ests[v], lsts[v], objval, SCIP_VARTYPE_INTEGER) );
1296  SCIP_CALL( SCIPaddVar(subscip, subvars[v]) );
1297  }
1298 
1299  /* create cumulative constraint */
1300  SCIP_CALL( SCIPcreateConsBasicCumulative(subscip, &cons, "cumulative",
1301  njobs, subvars, durations, demands, capacity) );
1302 
1303  /* set effective horizon */
1304  SCIP_CALL( SCIPsetHminCumulative(subscip, cons, hmin) );
1305  SCIP_CALL( SCIPsetHmaxCumulative(subscip, cons, hmax) );
1306 
1307  /* add cumulative constraint */
1308  SCIP_CALL( SCIPaddCons(subscip, cons) );
1309  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1310 
1311  /* set CP solver settings
1312  *
1313  * @note This "meta" setting has to be set first since this call overwrite all parameters including for example the
1314  * time limit.
1315  */
1317 
1318  /* do not abort subproblem on CTRL-C */
1319  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1320 
1321  /* disable output to console */
1322  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1323 
1324  /* set limits for the subproblem */
1325  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1326  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1327  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1328 
1329  /* forbid recursive call of heuristics and separators solving subMIPs */
1330  SCIP_CALL( SCIPsetSubscipsOff(subscip, TRUE) );
1331 
1332  /* solve single cumulative constraint by branch and bound */
1333  retcode = SCIPsolve(subscip);
1334 
1335  if( retcode != SCIP_OKAY )
1336  (*error) = TRUE;
1337  else
1338  {
1339  SCIPdebugMsg(subscip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1340 
1341  /* evaluated solution status */
1342  switch( SCIPgetStatus(subscip) )
1343  {
1344  case SCIP_STATUS_INFORUNBD:
1346  (*infeasible) = TRUE;
1347  (*solved) = TRUE;
1348  break;
1349  case SCIP_STATUS_UNBOUNDED:
1350  (*unbounded) = TRUE;
1351  (*solved) = TRUE;
1352  break;
1353  case SCIP_STATUS_OPTIMAL:
1354  {
1355  SCIP_SOL* sol;
1356  SCIP_Real solval;
1357 
1358  sol = SCIPgetBestSol(subscip);
1359  assert(sol != NULL);
1360 
1361  for( v = 0; v < njobs; ++v )
1362  {
1363  solval = SCIPgetSolVal(subscip, sol, subvars[v]);
1364 
1365  ests[v] = solval;
1366  lsts[v] = solval;
1367  }
1368  (*solved) = TRUE;
1369  break;
1370  }
1371  case SCIP_STATUS_NODELIMIT:
1373  case SCIP_STATUS_TIMELIMIT:
1374  case SCIP_STATUS_MEMLIMIT:
1376  case SCIP_STATUS_TERMINATE:
1377  /* transfer the global bound changes */
1378  for( v = 0; v < njobs; ++v )
1379  {
1380  ests[v] = SCIPvarGetLbGlobal(subvars[v]);
1381  lsts[v] = SCIPvarGetUbGlobal(subvars[v]);
1382  }
1383  (*solved) = FALSE;
1384  break;
1385 
1386  case SCIP_STATUS_UNKNOWN:
1388  case SCIP_STATUS_GAPLIMIT:
1390  case SCIP_STATUS_DUALLIMIT:
1391  case SCIP_STATUS_SOLLIMIT:
1394  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1395  return SCIP_INVALIDDATA;
1396  }
1397  }
1398 
1399  /* release all variables */
1400  for( v = 0; v < njobs; ++v )
1401  {
1402  SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1403  }
1404 
1405  SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
1406 
1407  return SCIP_OKAY;
1408 }
1409 
1410 /** solve single cumulative condition using SCIP and a single cumulative constraint */
1411 static
1412 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1414  SCIP* subscip;
1415 
1416  SCIP_RETCODE retcode;
1417 
1418  assert(njobs > 0);
1419 
1420  (*solved) = FALSE;
1421  (*infeasible) = FALSE;
1422  (*unbounded) = FALSE;
1423  (*error) = FALSE;
1424 
1425  SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1426 
1427  /* initialize the sub-problem */
1428  SCIP_CALL( SCIPcreate(&subscip) );
1429 
1430  /* create and solve the subproblem. catch possible errors */
1431  retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
1432  njobs, capacity, hmin, hmax,
1433  maxnodes, timelimit, memorylimit,
1434  ests, lsts,
1435  infeasible, unbounded, solved, error);
1436 
1437  /* free the subscip in any case */
1438  SCIP_CALL( SCIPfree(&subscip) );
1439 
1440  SCIP_CALL( retcode );
1441 
1442  return SCIP_OKAY;
1443 }
1444 
1445 #if 0
1446 /** solve single cumulative condition using SCIP and the time indexed formulation */
1447 static
1448 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1449 {
1450  SCIP* subscip;
1451  SCIP_VAR*** binvars;
1452  SCIP_RETCODE retcode;
1453  char name[SCIP_MAXSTRLEN];
1454  int minest;
1455  int maxlct;
1456  int t;
1457  int v;
1458 
1459  assert(njobs > 0);
1460 
1461  (*solved) = FALSE;
1462  (*infeasible) = FALSE;
1463  (*unbounded) = FALSE;
1464  (*error) = FALSE;
1465 
1466  SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
1467 
1468  /* initialize the sub-problem */
1469  SCIP_CALL( SCIPcreate(&subscip) );
1470 
1471  /* copy all plugins */
1473 
1474  /* create the subproblem */
1475  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1476 
1477  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
1478 
1479  minest = INT_MAX;
1480  maxlct = INT_MIN;
1481 
1482  /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1483  * partitioning constrain which forces that job starts
1484  */
1485  for( v = 0; v < njobs; ++v )
1486  {
1487  SCIP_CONS* cons;
1488  SCIP_Real objval;
1489  int timeinterval;
1490  int est;
1491  int lst;
1492 
1493  if( objvals == NULL )
1494  objval = 0.0;
1495  else
1496  objval = objvals[v];
1497 
1498  est = ests[v];
1499  lst = lsts[v];
1500 
1501  /* compute number of possible start points */
1502  timeinterval = lst - est + 1;
1503  assert(timeinterval > 0);
1504 
1505  /* compute the smallest earliest start time and largest latest completion time */
1506  minest = MIN(minest, est);
1507  maxlct = MAX(maxlct, lst + durations[v]);
1508 
1509  /* construct constraint name */
1510  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1511 
1512  SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1513 
1514  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
1515 
1516  for( t = 0; t < timeinterval; ++t )
1517  {
1518  SCIP_VAR* binvar;
1519 
1520  /* construct varibale name */
1521  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1522 
1523  SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1524  SCIP_CALL( SCIPaddVar(subscip, binvar) );
1525 
1526  /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1527  SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1528 
1529  binvars[v][t] = binvar;
1530  }
1531 
1532  /* add and release the set partitioning constraint */
1533  SCIP_CALL( SCIPaddCons(subscip, cons) );
1534  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1535  }
1536 
1537  /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1538  hmin = MAX(hmin, minest);
1539  hmax = MIN(hmax, maxlct);
1540  assert(hmin > INT_MIN);
1541  assert(hmax < INT_MAX);
1542  assert(hmin < hmax);
1543 
1544  /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1545  for( t = hmin; t < hmax; ++t )
1546  {
1547  SCIP_CONS* cons;
1548 
1549  /* construct constraint name */
1550  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1551 
1552  /* create an empty knapsack constraint */
1553  SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1554 
1555  /* add all jobs which potentially can be processed at that time point */
1556  for( v = 0; v < njobs; ++v )
1557  {
1558  int duration;
1559  int demand;
1560  int start;
1561  int end;
1562  int est;
1563  int lst;
1564  int k;
1565 
1566  est = ests[v];
1567  lst = lsts[v] ;
1568 
1569  duration = durations[v];
1570  assert(duration > 0);
1571 
1572  /* check if the varibale is processed potentially at time point t */
1573  if( t < est || t >= lst + duration )
1574  continue;
1575 
1576  demand = demands[v];
1577  assert(demand >= 0);
1578 
1579  start = MAX(t - duration + 1, est);
1580  end = MIN(t, lst);
1581 
1582  assert(start <= end);
1583 
1584  for( k = start; k <= end; ++k )
1585  {
1586  assert(binvars[v][k] != NULL);
1587  SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1588  }
1589  }
1590 
1591  /* add and release the knapsack constraint */
1592  SCIP_CALL( SCIPaddCons(subscip, cons) );
1593  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1594  }
1595 
1596  /* do not abort subproblem on CTRL-C */
1597  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1598 
1599  /* disable output to console */
1600  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1601 
1602  /* set limits for the subproblem */
1603  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1604  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1605  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1606 
1607  /* solve single cumulative constraint by branch and bound */
1608  retcode = SCIPsolve(subscip);
1609 
1610  if( retcode != SCIP_OKAY )
1611  (*error) = TRUE;
1612  else
1613  {
1614  SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1615 
1616  /* evaluated solution status */
1617  switch( SCIPgetStatus(subscip) )
1618  {
1619  case SCIP_STATUS_INFORUNBD:
1621  (*infeasible) = TRUE;
1622  (*solved) = TRUE;
1623  break;
1624  case SCIP_STATUS_UNBOUNDED:
1625  (*unbounded) = TRUE;
1626  (*solved) = TRUE;
1627  break;
1628  case SCIP_STATUS_OPTIMAL:
1629  {
1630  SCIP_SOL* sol;
1631 
1632  sol = SCIPgetBestSol(subscip);
1633  assert(sol != NULL);
1634 
1635  for( v = 0; v < njobs; ++v )
1636  {
1637  int timeinterval;
1638  int est;
1639  int lst;
1640 
1641  est = ests[v];
1642  lst = lsts[v];
1643 
1644  /* compute number of possible start points */
1645  timeinterval = lst - est + 1;
1646 
1647  /* check which binary varibale is set to one */
1648  for( t = 0; t < timeinterval; ++t )
1649  {
1650  if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1651  {
1652  ests[v] = est + t;
1653  lsts[v] = est + t;
1654  break;
1655  }
1656  }
1657  }
1658 
1659  (*solved) = TRUE;
1660  break;
1661  }
1662  case SCIP_STATUS_NODELIMIT:
1664  case SCIP_STATUS_TIMELIMIT:
1665  case SCIP_STATUS_MEMLIMIT:
1667  /* transfer the global bound changes */
1668  for( v = 0; v < njobs; ++v )
1669  {
1670  int timeinterval;
1671  int est;
1672  int lst;
1673 
1674  est = ests[v];
1675  lst = lsts[v];
1676 
1677  /* compute number of possible start points */
1678  timeinterval = lst - est + 1;
1679 
1680  /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1681  for( t = 0; t < timeinterval; ++t )
1682  {
1683  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1684  {
1685  ests[v] = est + t;
1686  break;
1687  }
1688  }
1689 
1690  /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1691  for( t = timeinterval - 1; t >= 0; --t )
1692  {
1693  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1694  {
1695  lsts[v] = est + t;
1696  break;
1697  }
1698  }
1699  }
1700  (*solved) = FALSE;
1701  break;
1702 
1703  case SCIP_STATUS_UNKNOWN:
1705  case SCIP_STATUS_GAPLIMIT:
1706  case SCIP_STATUS_SOLLIMIT:
1708  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1709  return SCIP_INVALIDDATA;
1710  }
1711  }
1712 
1713  /* release all variables */
1714  for( v = 0; v < njobs; ++v )
1715  {
1716  int timeinterval;
1717  int est;
1718  int lst;
1719 
1720  est = ests[v];
1721  lst = lsts[v];
1722 
1723  /* compute number of possible start points */
1724  timeinterval = lst - est + 1;
1725 
1726  for( t = 0; t < timeinterval; ++t )
1727  {
1728  SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1729  }
1730  SCIPfreeBufferArray(subscip, &binvars[v]);
1731  }
1732 
1733  SCIPfreeBufferArray(subscip, &binvars);
1734 
1735  SCIP_CALL( SCIPfree(&subscip) );
1736 
1737  return SCIP_OKAY;
1738 }
1739 #endif
1740 
1741 /**@} */
1742 
1743 /**@name Constraint handler data
1744  *
1745  * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1746  * handler.
1747  *
1748  * @{
1749  */
1750 
1751 /** creates constaint handler data for cumulative constraint handler */
1752 static
1754  SCIP* scip, /**< SCIP data structure */
1755  SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1756  SCIP_EVENTHDLR* eventhdlr /**< event handler */
1757  )
1758 {
1759  /* create precedence constraint handler data */
1760  assert(scip != NULL);
1761  assert(conshdlrdata != NULL);
1762  assert(eventhdlr != NULL);
1763 
1764  SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
1765 
1766  /* set event handler for checking if bounds of start time variables are tighten */
1767  (*conshdlrdata)->eventhdlr = eventhdlr;
1768 
1769  /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1770  (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1771 
1772 #ifdef SCIP_STATISTIC
1773  (*conshdlrdata)->nlbtimetable = 0;
1774  (*conshdlrdata)->nubtimetable = 0;
1775  (*conshdlrdata)->ncutofftimetable = 0;
1776  (*conshdlrdata)->nlbedgefinder = 0;
1777  (*conshdlrdata)->nubedgefinder = 0;
1778  (*conshdlrdata)->ncutoffedgefinder = 0;
1779  (*conshdlrdata)->ncutoffoverload = 0;
1780  (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1781 
1782  (*conshdlrdata)->nirrelevantjobs = 0;
1783  (*conshdlrdata)->nalwaysruns = 0;
1784  (*conshdlrdata)->nremovedlocks = 0;
1785  (*conshdlrdata)->ndualfixs = 0;
1786  (*conshdlrdata)->ndecomps = 0;
1787  (*conshdlrdata)->ndualbranchs = 0;
1788  (*conshdlrdata)->nallconsdualfixs = 0;
1789  (*conshdlrdata)->naddedvarbounds = 0;
1790  (*conshdlrdata)->naddeddisjunctives = 0;
1791 #endif
1792 
1793  return SCIP_OKAY;
1794 }
1795 
1796 /** frees constraint handler data for logic or constraint handler */
1797 static
1798 void conshdlrdataFree(
1799  SCIP* scip, /**< SCIP data structure */
1800  SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1801  )
1802 {
1803  assert(conshdlrdata != NULL);
1804  assert(*conshdlrdata != NULL);
1805 
1806  SCIPfreeBlockMemory(scip, conshdlrdata);
1807 }
1808 
1809 /**@} */
1810 
1811 
1812 /**@name Constraint data methods
1813  *
1814  * @{
1815  */
1816 
1817 /** catches bound change events for all variables in transformed cumulative constraint */
1818 static
1820  SCIP* scip, /**< SCIP data structure */
1821  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1822  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1823  )
1824 {
1825  int v;
1826 
1827  assert(scip != NULL);
1828  assert(consdata != NULL);
1829  assert(eventhdlr != NULL);
1830 
1831  /* catch event for every single variable */
1832  for( v = 0; v < consdata->nvars; ++v )
1833  {
1834  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1835  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1836  }
1837 
1838  return SCIP_OKAY;
1839 }
1840 
1841 /** drops events for variable at given position */
1842 static
1844  SCIP* scip, /**< SCIP data structure */
1845  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1846  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1847  int pos /**< array position of variable to catch bound change events for */
1848  )
1849 {
1850  assert(scip != NULL);
1851  assert(consdata != NULL);
1852  assert(eventhdlr != NULL);
1853  assert(0 <= pos && pos < consdata->nvars);
1854  assert(consdata->vars[pos] != NULL);
1855 
1856  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1857  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1858 
1859  return SCIP_OKAY;
1860 }
1861 
1862 /** drops bound change events for all variables in transformed linear constraint */
1863 static
1865  SCIP* scip, /**< SCIP data structure */
1866  SCIP_CONSDATA* consdata, /**< linear constraint data */
1867  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1868  )
1869 {
1870  int v;
1871 
1872  assert(scip != NULL);
1873  assert(consdata != NULL);
1874 
1875  /* drop event of every single variable */
1876  for( v = 0; v < consdata->nvars; ++v )
1877  {
1878  SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1879  }
1880 
1881  return SCIP_OKAY;
1882 }
1883 
1884 /** initialize variable lock data structure */
1885 static
1886 void initializeLocks(
1887  SCIP_CONSDATA* consdata, /**< constraint data */
1888  SCIP_Bool locked /**< should the variable be locked? */
1889  )
1890 {
1891  int nvars;
1892  int v;
1893 
1894  nvars = consdata->nvars;
1895 
1896  /* initialize locking arrays */
1897  for( v = 0; v < nvars; ++v )
1898  {
1899  consdata->downlocks[v] = locked;
1900  consdata->uplocks[v] = locked;
1901  }
1902 }
1903 
1904 /** creates constraint data of cumulative constraint */
1905 static
1907  SCIP* scip, /**< SCIP data structure */
1908  SCIP_CONSDATA** consdata, /**< pointer to consdata */
1909  SCIP_VAR** vars, /**< array of integer variables */
1910  SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1911  int* durations, /**< array containing corresponding durations */
1912  int* demands, /**< array containing corresponding demands */
1913  int nvars, /**< number of variables */
1914  int capacity, /**< available cumulative capacity */
1915  int hmin, /**< left bound of time axis to be considered (including hmin) */
1916  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1917  SCIP_Bool check /**< is the corresponding constraint a check constraint */
1918  )
1919 {
1920  int v;
1921 
1922  assert(scip != NULL);
1923  assert(consdata != NULL);
1924  assert(vars != NULL || nvars > 0);
1925  assert(demands != NULL);
1926  assert(durations != NULL);
1927  assert(capacity >= 0);
1928  assert(hmin >= 0);
1929  assert(hmin < hmax);
1930 
1931  /* create constraint data */
1932  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1933 
1934  (*consdata)->hmin = hmin;
1935  (*consdata)->hmax = hmax;
1936 
1937  (*consdata)->capacity = capacity;
1938  (*consdata)->demandrows = NULL;
1939  (*consdata)->demandrowssize = 0;
1940  (*consdata)->ndemandrows = 0;
1941  (*consdata)->scoverrows = NULL;
1942  (*consdata)->nscoverrows = 0;
1943  (*consdata)->scoverrowssize = 0;
1944  (*consdata)->bcoverrows = NULL;
1945  (*consdata)->nbcoverrows = 0;
1946  (*consdata)->bcoverrowssize = 0;
1947  (*consdata)->nvars = nvars;
1948  (*consdata)->varssize = nvars;
1949  (*consdata)->signature = 0;
1950  (*consdata)->validsignature = FALSE;
1951  (*consdata)->normalized = FALSE;
1952  (*consdata)->covercuts = FALSE;
1953  (*consdata)->propagated = FALSE;
1954  (*consdata)->varbounds = FALSE;
1955  (*consdata)->triedsolving = FALSE;
1956 
1957  if( nvars > 0 )
1958  {
1959  assert(vars != NULL); /* for flexelint */
1960 
1961  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1962  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1963  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1964  (*consdata)->linkingconss = NULL;
1965 
1966  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1967  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1968 
1969  /* initialize variable lock data structure; the locks are only used if the constraint is a check constraint */
1970  initializeLocks(*consdata, check);
1971 
1972  if( linkingconss != NULL )
1973  {
1974  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
1975  }
1976 
1977  /* transform variables, if they are not yet transformed */
1978  if( SCIPisTransformed(scip) )
1979  {
1980  SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
1981 
1982  /* get transformed variables and do NOT captures these */
1983  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1984 
1985  /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
1986  * been multi-aggregated
1987  */
1988  for( v = 0; v < nvars; ++v )
1989  {
1990  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
1991  }
1992 
1993  if( linkingconss != NULL )
1994  {
1995  /* get transformed constraints and captures these */
1996  SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
1997 
1998  for( v = 0; v < nvars; ++v )
1999  assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
2000  }
2001  }
2002 
2003 #ifndef NDEBUG
2004  /* only binary and integer variables can be used in cumulative constraints
2005  * for fractional variable values, the constraint cannot be checked
2006  */
2007  for( v = 0; v < (*consdata)->nvars; ++v )
2008  assert(SCIPvarGetType((*consdata)->vars[v]) <= SCIP_VARTYPE_INTEGER);
2009 #endif
2010  }
2011  else
2012  {
2013  (*consdata)->vars = NULL;
2014  (*consdata)->downlocks = NULL;
2015  (*consdata)->uplocks = NULL;
2016  (*consdata)->demands = NULL;
2017  (*consdata)->durations = NULL;
2018  (*consdata)->linkingconss = NULL;
2019  }
2020 
2021  /* initialize values for running propagation algorithms efficiently */
2022  (*consdata)->resstrength1 = -1.0;
2023  (*consdata)->resstrength2 = -1.0;
2024  (*consdata)->cumfactor1 = -1.0;
2025  (*consdata)->disjfactor1 = -1.0;
2026  (*consdata)->disjfactor2 = -1.0;
2027  (*consdata)->estimatedstrength = -1.0;
2028 
2029  SCIPstatistic( (*consdata)->maxpeak = -1 );
2030 
2031  return SCIP_OKAY;
2032 }
2033 
2034 /** releases LP rows of constraint data and frees rows array */
2035 static
2037  SCIP* scip, /**< SCIP data structure */
2038  SCIP_CONSDATA** consdata /**< constraint data */
2039  )
2040 {
2041  int r;
2042 
2043  assert(consdata != NULL);
2044  assert(*consdata != NULL);
2045 
2046  for( r = 0; r < (*consdata)->ndemandrows; ++r )
2047  {
2048  assert((*consdata)->demandrows[r] != NULL);
2049  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
2050  }
2051 
2052  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
2053 
2054  (*consdata)->ndemandrows = 0;
2055  (*consdata)->demandrowssize = 0;
2056 
2057  /* free rows of cover cuts */
2058  for( r = 0; r < (*consdata)->nscoverrows; ++r )
2059  {
2060  assert((*consdata)->scoverrows[r] != NULL);
2061  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
2062  }
2063 
2064  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
2065 
2066  (*consdata)->nscoverrows = 0;
2067  (*consdata)->scoverrowssize = 0;
2068 
2069  for( r = 0; r < (*consdata)->nbcoverrows; ++r )
2070  {
2071  assert((*consdata)->bcoverrows[r] != NULL);
2072  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2073  }
2074 
2075  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2076 
2077  (*consdata)->nbcoverrows = 0;
2078  (*consdata)->bcoverrowssize = 0;
2079 
2080  (*consdata)->covercuts = FALSE;
2081 
2082  return SCIP_OKAY;
2083 }
2084 
2085 /** frees a cumulative constraint data */
2086 static
2088  SCIP* scip, /**< SCIP data structure */
2089  SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2090  )
2091 {
2092  int varssize;
2093  int nvars;
2094 
2095  assert(consdata != NULL);
2096  assert(*consdata != NULL);
2097 
2098  nvars = (*consdata)->nvars;
2099  varssize = (*consdata)->varssize;
2100 
2101  if( varssize > 0 )
2102  {
2103  int v;
2104 
2105  /* release and free the rows */
2106  SCIP_CALL( consdataFreeRows(scip, consdata) );
2107 
2108  /* release the linking constraints if they were generated */
2109  if( (*consdata)->linkingconss != NULL )
2110  {
2111  for( v = nvars-1; v >= 0; --v )
2112  {
2113  assert((*consdata)->linkingconss[v] != NULL );
2114  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2115  }
2116 
2117  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2118  }
2119 
2120  /* free arrays */
2121  SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2122  SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2123  SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2124  SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2125  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2126  }
2127 
2128  /* free memory */
2129  SCIPfreeBlockMemory(scip, consdata);
2130 
2131  return SCIP_OKAY;
2132 }
2133 
2134 /** prints cumulative constraint to file stream */
2135 static
2136 void consdataPrint(
2137  SCIP* scip, /**< SCIP data structure */
2138  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2139  FILE* file /**< output file (or NULL for standard output) */
2140  )
2141 {
2142  int v;
2143 
2144  assert(consdata != NULL);
2145 
2146  /* print coefficients */
2147  SCIPinfoMessage( scip, file, "cumulative(");
2148 
2149  for( v = 0; v < consdata->nvars; ++v )
2150  {
2151  assert(consdata->vars[v] != NULL);
2152  if( v > 0 )
2153  SCIPinfoMessage(scip, file, ", ");
2154  SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2155  SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2156  consdata->durations[v], consdata->demands[v]);
2157  }
2158  SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2159 }
2160 
2161 /** deletes coefficient at given position from constraint data */
2162 static
2164  SCIP* scip, /**< SCIP data structure */
2165  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2166  SCIP_CONS* cons, /**< knapsack constraint */
2167  int pos /**< position of coefficient to delete */
2168  )
2169 {
2170  SCIP_CONSHDLR* conshdlr;
2171  SCIP_CONSHDLRDATA* conshdlrdata;
2172 
2173  assert(scip != NULL);
2174  assert(consdata != NULL);
2175  assert(cons != NULL);
2176  assert(SCIPconsIsTransformed(cons));
2177  assert(!SCIPinProbing(scip));
2178 
2179  SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2180  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2181 
2182  /* remove the rounding locks for the deleted variable */
2183  SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2184 
2185  consdata->downlocks[pos] = FALSE;
2186  consdata->uplocks[pos] = FALSE;
2187 
2188  if( consdata->linkingconss != NULL )
2189  {
2190  SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2191  }
2192 
2193  /* get event handler */
2194  conshdlr = SCIPconsGetHdlr(cons);
2195  assert(conshdlr != NULL);
2196  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2197  assert(conshdlrdata != NULL);
2198  assert(conshdlrdata->eventhdlr != NULL);
2199 
2200  /* drop events */
2201  SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2202 
2203  SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2204  SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2205 
2206  /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2207  * position
2208  */
2209  if( pos != consdata->nvars - 1 )
2210  {
2211  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2212  consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2213  consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2214  consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2215  consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2216 
2217  if( consdata->linkingconss != NULL )
2218  {
2219  consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2220  }
2221  }
2222 
2223  consdata->nvars--;
2224  consdata->validsignature = FALSE;
2225  consdata->normalized = FALSE;
2226 
2227  return SCIP_OKAY;
2228 }
2229 
2230 /** collect linking constraints for each integer variable */
2231 static
2233  SCIP* scip, /**< SCIP data structure */
2234  SCIP_CONSDATA* consdata /**< pointer to consdata */
2235  )
2236 {
2237  int nvars;
2238  int v;
2239 
2240  assert(scip != NULL);
2241  assert(consdata != NULL);
2242 
2243  nvars = consdata->nvars;
2244  assert(nvars > 0);
2245  assert(consdata->linkingconss == NULL);
2246 
2247  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2248 
2249  for( v = 0; v < nvars; ++v )
2250  {
2251  SCIP_CONS* cons;
2252  SCIP_VAR* var;
2253 
2254  var = consdata->vars[v];
2255  assert(var != NULL);
2256 
2257  SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2258 
2259  /* create linking constraint if it does not exist yet */
2260  if( !SCIPexistsConsLinking(scip, var) )
2261  {
2262  char name[SCIP_MAXSTRLEN];
2263 
2264  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2265 
2266  /* creates and captures an linking constraint */
2267  SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2268  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2269  SCIP_CALL( SCIPaddCons(scip, cons) );
2270  consdata->linkingconss[v] = cons;
2271  }
2272  else
2273  {
2274  consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2275  SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2276  }
2277 
2278  assert(SCIPexistsConsLinking(scip, var));
2279  assert(consdata->linkingconss[v] != NULL);
2280  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2281  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2282  }
2283 
2284  return SCIP_OKAY;
2285 }
2286 
2287 /**@} */
2288 
2289 
2290 /**@name Check methods
2291  *
2292  * @{
2293  */
2294 
2295 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2296  * given solution is satisfied
2297  */
2298 static
2300  SCIP* scip, /**< SCIP data structure */
2301  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2302  int nvars, /**< number of variables (jobs) */
2303  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2304  int* durations, /**< array containing corresponding durations */
2305  int* demands, /**< array containing corresponding demands */
2306  int capacity, /**< available cumulative capacity */
2307  int hmin, /**< left bound of time axis to be considered (including hmin) */
2308  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2309  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2310  SCIP_CONS* cons, /**< constraint which is checked */
2311  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2312  )
2313 {
2314  int* startsolvalues; /* stores when each job is starting */
2315  int* endsolvalues; /* stores when each job ends */
2316  int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2317  int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2318 
2319  int freecapacity;
2320  int curtime; /* point in time which we are just checking */
2321  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2322  int j;
2323 
2324  SCIP_Real absviol;
2325  SCIP_Real relviol;
2326 
2327  assert(scip != NULL);
2328  assert(violated != NULL);
2329 
2330  (*violated) = FALSE;
2331 
2332  if( nvars == 0 )
2333  return SCIP_OKAY;
2334 
2335  assert(vars != NULL);
2336  assert(demands != NULL);
2337  assert(durations != NULL);
2338 
2339  /* compute time points where we have to check whether capacity constraint is infeasible or not */
2340  SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2341  SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2342  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2343  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2344 
2345  /* assign variables, start and endpoints to arrays */
2346  for ( j = 0; j < nvars; ++j )
2347  {
2348  int solvalue;
2349 
2350  /* the constraint of the cumulative constraint handler should be called after the integrality check */
2351  assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2352 
2353  solvalue = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2354 
2355  /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2356  * jobs which start before hmin to hmin
2357  */
2358  startsolvalues[j] = MAX(solvalue, hmin);
2359  startindices[j] = j;
2360 
2361  endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2362  endindices[j] = j;
2363  }
2364 
2365  /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2366  * corresponding indices in the same way)
2367  */
2368  SCIPsortIntInt(startsolvalues, startindices, nvars);
2369  SCIPsortIntInt(endsolvalues, endindices, nvars);
2370 
2371  endindex = 0;
2372  freecapacity = capacity;
2373  absviol = 0.0;
2374  relviol = 0.0;
2375 
2376  /* check each start point of a job whether the capacity is kept or not */
2377  for( j = 0; j < nvars; ++j )
2378  {
2379  /* only check intervals [hmin,hmax) */
2380  curtime = startsolvalues[j];
2381 
2382  if( curtime >= hmax )
2383  break;
2384 
2385  /* subtract all capacity needed up to this point */
2386  freecapacity -= demands[startindices[j]];
2387  while( j+1 < nvars && startsolvalues[j+1] == curtime )
2388  {
2389  j++;
2390  freecapacity -= demands[startindices[j]];
2391  }
2392 
2393  /* free all capacity usages of jobs that are no longer running */
2394  while( endindex < nvars && curtime >= endsolvalues[endindex] )
2395  {
2396  freecapacity += demands[endindices[endindex]];
2397  ++endindex;
2398  }
2399  assert(freecapacity <= capacity);
2400 
2401  /* update absolute and relative violation */
2402  if( absviol < (SCIP_Real) (-freecapacity) )
2403  {
2404  absviol = -freecapacity;
2405  relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
2406  }
2407 
2408  /* check freecapacity to be smaller than zero */
2409  if( freecapacity < 0 && curtime >= hmin )
2410  {
2411  SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2412  (*violated) = TRUE;
2413 
2414  if( printreason )
2415  {
2416  int i;
2417 
2418  /* first state the violated constraints */
2419  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2420 
2421  /* second state the reason */
2422  SCIPinfoMessage(scip, NULL,
2423  ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2424  curtime, capacity, capacity - freecapacity);
2425 
2426  for( i = 0; i <= j; ++i )
2427  {
2428  if( startsolvalues[i] + durations[startindices[i]] > curtime )
2429  {
2430  SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2431  SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2432  demands[startindices[i]]);
2433  }
2434  }
2435  }
2436  break;
2437  }
2438  } /*lint --e{850}*/
2439 
2440  /* update constraint violation in solution */
2441  if( sol != NULL )
2442  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
2443 
2444  /* free all buffer arrays */
2445  SCIPfreeBufferArray(scip, &endindices);
2446  SCIPfreeBufferArray(scip, &startindices);
2447  SCIPfreeBufferArray(scip, &endsolvalues);
2448  SCIPfreeBufferArray(scip, &startsolvalues);
2449 
2450  return SCIP_OKAY;
2451 }
2452 
2453 /** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2454  * least zero or not. If not (*violated) is set to TRUE
2455  */
2456 static
2458  SCIP* scip, /**< SCIP data structure */
2459  SCIP_CONS* cons, /**< constraint to be checked */
2460  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2461  SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2462  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2463  )
2464 {
2465  SCIP_CONSDATA* consdata;
2466 
2467  assert(scip != NULL);
2468  assert(cons != NULL);
2469  assert(violated != NULL);
2470 
2471  SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2472 
2473  consdata = SCIPconsGetData(cons);
2474  assert(consdata != NULL);
2475 
2476  /* check the cumulative condition */
2477  SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2478  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2479  violated, cons, printreason) );
2480 
2481  return SCIP_OKAY;
2482 }
2483 
2484 /**@} */
2485 
2486 /**@name Conflict analysis
2487  *
2488  * @{
2489  */
2490 
2491 /** resolves the propagation of the core time algorithm */
2492 static
2494  SCIP* scip, /**< SCIP data structure */
2495  int nvars, /**< number of start time variables (activities) */
2496  SCIP_VAR** vars, /**< array of start time variables */
2497  int* durations, /**< array of durations */
2498  int* demands, /**< array of demands */
2499  int capacity, /**< cumulative capacity */
2500  int hmin, /**< left bound of time axis to be considered (including hmin) */
2501  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2502  SCIP_VAR* infervar, /**< inference variable */
2503  int inferdemand, /**< demand of the inference variable */
2504  int inferpeak, /**< time point which causes the propagation */
2505  int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2506  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2507  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2508  int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2509  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2510  )
2511 {
2512  SCIP_VAR* var;
2513  SCIP_Bool* reported;
2514  int duration;
2515  int maxlst;
2516  int minect;
2517  int ect;
2518  int lst;
2519  int j;
2520 
2521  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
2522 
2523  SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2524  SCIPvarGetName(infervar), inferdemand, inferpeak);
2525  assert(nvars > 0);
2526 
2527  /* adjusted capacity */
2528  capacity -= inferdemand;
2529  maxlst = INT_MIN;
2530  minect = INT_MAX;
2531 
2532  SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2533  BMSclearMemoryArray(reported, nvars);
2534 
2535  /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2536  * inference peak and those where the current conflict bounds provide a core at the inference peak
2537  */
2538  for( j = 0; j < nvars && capacity >= 0; ++j )
2539  {
2540  var = vars[j];
2541  assert(var != NULL);
2542 
2543  /* skip inference variable */
2544  if( var == infervar )
2545  continue;
2546 
2547  duration = durations[j];
2548  assert(duration > 0);
2549 
2550  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2551  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2552  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2553  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2554  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2555 
2556  SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2558  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2559 
2560  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2561  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2562 
2563  /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2564  * that job without adding it the explanation
2565  */
2566  if( inferpeak < ect && lst <= inferpeak )
2567  {
2568  capacity -= demands[j];
2569  reported[j] = TRUE;
2570 
2571  maxlst = MAX(maxlst, lst);
2572  minect = MIN(minect, ect);
2573  assert(maxlst < minect);
2574 
2575  if( explanation != NULL )
2576  explanation[j] = TRUE;
2577 
2578  continue;
2579  }
2580 
2581  /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2582  * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2583  * not part of the conflict yet we get the global bounds back.
2584  */
2585  ect = SCIPconvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2586  lst = SCIPconvertRealToInt(scip, SCIPgetConflictVarUb(scip, var));
2587 
2588  /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2589  * of that job without and collect the job as part of the explanation
2590  *
2591  * @note we do not need to reported that job to SCIP since the required bounds are already reported
2592  */
2593  if( inferpeak < ect && lst <= inferpeak )
2594  {
2595  capacity -= demands[j];
2596  reported[j] = TRUE;
2597 
2598  maxlst = MAX(maxlst, lst);
2599  minect = MIN(minect, ect);
2600  assert(maxlst < minect);
2601 
2602  if( explanation != NULL )
2603  explanation[j] = TRUE;
2604  }
2605  }
2606 
2607  if( capacity >= 0 )
2608  {
2609  int* cands;
2610  int* canddemands;
2611  int ncands;
2612  int c;
2613 
2614  SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2615  SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2616  ncands = 0;
2617 
2618  /* collect all cores of the variables which lay in the considered time window except the inference variable */
2619  for( j = 0; j < nvars; ++j )
2620  {
2621  var = vars[j];
2622  assert(var != NULL);
2623 
2624  /* skip inference variable */
2625  if( var == infervar || reported[j] )
2626  continue;
2627 
2628  duration = durations[j];
2629  assert(duration > 0);
2630 
2631  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2632  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2633  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2634  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2635  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2636 
2637  /* collect local core information */
2638  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2639  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2640 
2641  SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2642  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2643  SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2644 
2645  /* check if the inference peak is part of the core */
2646  if( inferpeak < ect && lst <= inferpeak )
2647  {
2648  cands[ncands] = j;
2649  canddemands[ncands] = demands[j];
2650  ncands++;
2651 
2652  capacity -= demands[j];
2653  }
2654  }
2655 
2656  /* sort candidates indices w.r.t. their demands */
2657  SCIPsortDownIntInt(canddemands, cands, ncands);
2658 
2659  assert(capacity < 0);
2660  assert(ncands > 0);
2661 
2662  /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2663  while( capacity + canddemands[ncands-1] < 0 )
2664  {
2665  ncands--;
2666  capacity += canddemands[ncands];
2667  assert(ncands > 0);
2668  }
2669 
2670  /* compute the size (number of time steps) of the job cores */
2671  for( c = 0; c < ncands; ++c )
2672  {
2673  var = vars[cands[c]];
2674  assert(var != NULL);
2675 
2676  duration = durations[cands[c]];
2677 
2678  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2679  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2680 
2681  maxlst = MAX(maxlst, lst);
2682  minect = MIN(minect, ect);
2683  assert(maxlst < minect);
2684  }
2685 
2686  SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2687  assert(inferpeak >= maxlst);
2688  assert(inferpeak < minect);
2689 
2690  /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2691  if( relaxedpeak < inferpeak )
2692  {
2693  inferpeak = MAX(maxlst, relaxedpeak);
2694  }
2695  else if( relaxedpeak > inferpeak )
2696  {
2697  inferpeak = MIN(minect-1, relaxedpeak);
2698  }
2699  assert(inferpeak >= hmin);
2700  assert(inferpeak < hmax);
2701  assert(inferpeak >= maxlst);
2702  assert(inferpeak < minect);
2703 
2704  /* post all necessary bound changes */
2705  for( c = 0; c < ncands; ++c )
2706  {
2707  var = vars[cands[c]];
2708  assert(var != NULL);
2709 
2710  if( usebdwidening )
2711  {
2712  duration = durations[cands[c]];
2713 
2714  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2715  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2716  }
2717  else
2718  {
2719  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2720  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2721  }
2722 
2723  if( explanation != NULL )
2724  explanation[cands[c]] = TRUE;
2725  }
2726 
2727  SCIPfreeBufferArray(scip, &canddemands);
2728  SCIPfreeBufferArray(scip, &cands);
2729  }
2730 
2731  SCIPfreeBufferArray(scip, &reported);
2732 
2733  if( provedpeak != NULL )
2734  *provedpeak = inferpeak;
2735 
2736  return SCIP_OKAY;
2737 }
2738 
2739 #if 0
2740 /** repropagation of edge finding algorithm simplified version from Petr Vilim only a small subset is reported such that
2741  * energy in total and for bound change is enough
2742  */
2743 static
2744 SCIP_RETCODE resolvePropagationEdgeFinding(
2745  SCIP* scip, /**< SCIP data structure */
2746  int nvars, /**< number of start time variables (activities) */
2747  SCIP_VAR** vars, /**< array of start time variables */
2748  int* durations, /**< array of durations */
2749  int hmin, /**< left bound of time axis to be considered (including hmin) */
2750  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2751  SCIP_VAR* infervar, /**< variable whose bound change is to be explained */
2752  INFERINFO inferinfo, /**< inference info containing position of correct bdchgids */
2753  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2754  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2755  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2756  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2757  )
2758 {
2759  int est;
2760  int lct;
2761  int j;
2762 
2763  /* ???????????????????? do bound widening */
2764 
2765  assert(scip != NULL);
2766  assert(nvars > 0);
2767  assert(inferInfoGetProprule(inferinfo) == PROPRULE_2_EDGEFINDING);
2768 
2769  SCIPdebugMsg(scip, "repropagate edge-finding with short reasons for variable <%s>\n", SCIPvarGetName(infervar));
2770 
2771  if( boundtype == SCIP_BOUNDTYPE_LOWER )
2772  {
2773  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
2774  }
2775  else
2776  {
2777  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
2778  }
2779 
2780  est = inferInfoGetData1(inferinfo);
2781  lct = inferInfoGetData2(inferinfo);
2782  assert(est < lct);
2783 
2784  /* collect the energies of all variables in [est_omega, lct_omega] */
2785  for( j = 0; j < nvars; ++j )
2786  {
2787  SCIP_VAR* var;
2788  SCIP_Bool left;
2789  SCIP_Bool right;
2790  int duration;
2791  int lb;
2792  int ub;
2793 
2794  var = vars[j];
2795  assert(var != NULL);
2796 
2797  if( var == infervar )
2798  {
2799  if( explanation != NULL )
2800  explanation[j] = TRUE;
2801 
2802  continue;
2803  }
2804 
2805  lb = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
2806  ub = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2807 
2808  duration = durations[j];
2809  assert(duration > 0);
2810 
2811  /* in case the earliest start time is equal to hmin we have to also consider the jobs which run in that region
2812  * since we use adjusted jobs during the propagation
2813  */
2814  left = (est == hmin && lb + duration > hmin) || lb >= est;
2815 
2816  /* in case the latest completion time is equal to hmax we have to also consider the jobs which run in that region
2817  * since we use adjusted jobs during the propagation
2818  */
2819  right = (lct == hmax && ub < hmax) || ub + duration <= lct;
2820 
2821  /* store all jobs running in [est_omega; lct_omega] */
2822  if( left && right )
2823  {
2824  /* check if bound widening should be used */
2825  if( usebdwidening )
2826  {
2827  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(lct - duration)) );
2828  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(est)) );
2829  }
2830  else
2831  {
2832  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2833  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2834  }
2835 
2836  if( explanation != NULL )
2837  explanation[j] = TRUE;
2838  }
2839  }
2840 
2841  return SCIP_OKAY;
2842 }
2843 #endif
2844 
2845 /** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2846 static
2847 int computeOverlap(
2848  int begin, /**< begin of the times interval */
2849  int end, /**< end of time interval */
2850  int est, /**< earliest start time */
2851  int lst, /**< latest start time */
2852  int duration /**< duration of the job */
2853  )
2854 {
2855  int left;
2856  int right;
2857  int ect;
2858  int lct;
2859 
2860  ect = est + duration;
2861  lct = lst + duration;
2862 
2863  /* check if job runs completely within [begin,end) */
2864  if( lct <= end && est >= begin )
2865  return duration;
2866 
2867  assert(lst <= end && ect >= begin);
2868 
2869  left = ect - begin;
2870  assert(left > 0);
2871 
2872  right = end - lst;
2873  assert(right > 0);
2874 
2875  return MIN3(left, right, end - begin);
2876 }
2877 
2878 /** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2879  * reason
2880  *
2881  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2882  */
2883 static
2885  SCIP* scip, /**< SCIP data structure */
2886  int nvars, /**< number of start time variables (activities) */
2887  SCIP_VAR** vars, /**< array of start time variables */
2888  int* durations, /**< array of durations */
2889  int* demands, /**< array of demands */
2890  int capacity, /**< capacity of the cumulative condition */
2891  int begin, /**< begin of the time window */
2892  int end, /**< end of the time window */
2893  SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2894  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2895  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2896  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2897  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2898  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2899  )
2900 {
2901  int* locenergies;
2902  int* overlaps;
2903  int* idxs;
2904 
2905  SCIP_Longint requiredenergy;
2906  int v;
2907 
2908  SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2909  SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2910  SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2911 
2912  /* energy which needs be explained */
2913  requiredenergy = ((SCIP_Longint) end - begin) * capacity;
2914 
2915  SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %" SCIP_LONGINT_FORMAT ")\n", begin, end, capacity, requiredenergy);
2916 
2917  /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2918  * takes
2919  */
2920  for( v = 0; v < nvars; ++v )
2921  {
2922  SCIP_VAR* var;
2923  int glbenergy;
2924  int duration;
2925  int demand;
2926  int est;
2927  int lst;
2928 
2929  var = vars[v];
2930  assert(var != NULL);
2931 
2932  locenergies[v] = 0;
2933  overlaps[v] = 0;
2934  idxs[v] = v;
2935 
2936  demand = demands[v];
2937  assert(demand > 0);
2938 
2939  duration = durations[v];
2940  assert(duration > 0);
2941 
2942  /* check if the variable equals the inference variable (the one which was propagated) */
2943  if( infervar == var )
2944  {
2945  int overlap;
2946  int right;
2947  int left;
2948 
2949  assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2950 
2951  SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2952  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2953  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2954 
2955  /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2956  * which is necessary from the inference variable
2957  */
2958  if( boundtype == SCIP_BOUNDTYPE_UPPER )
2959  {
2960  int lct;
2961 
2962  /* get the latest start time of the infer start time variable before the propagation took place */
2963  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2964 
2965  /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2966  * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2967  * scheduled w.r.t. its latest start time
2968  */
2969  assert(lst < end);
2970 
2971  /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2972  * interval (before the propagation)
2973  */
2974  right = MIN3(end - lst, end - begin, duration);
2975 
2976  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2977  assert(right > 0);
2978 
2979  lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2980  assert(begin <= lct);
2981  assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
2982 
2983  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2984  left = MIN(lct - begin + 1, end - begin);
2985  assert(left > 0);
2986 
2987  /* compute the minimum overlap; */
2988  overlap = MIN(left, right);
2989  assert(overlap > 0);
2990  assert(overlap <= end - begin);
2991  assert(overlap <= duration);
2992 
2993  if( usebdwidening )
2994  {
2995  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2996  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2997  }
2998  else
2999  {
3000  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
3001  }
3002  }
3003  else
3004  {
3005  int ect;
3006 
3007  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3008 
3009  /* get the earliest completion time of the infer start time variable before the propagation took place */
3010  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
3011 
3012  /* the earliest start time of the inference start time variable before the propagation needs to be larger as
3013  * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
3014  * the job is scheduled w.r.t. its earliest start time
3015  */
3016  assert(ect > begin);
3017 
3018  /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
3019  * interval (before the propagation)
3020  */
3021  left = MIN3(ect - begin, end - begin, duration);
3022 
3023  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
3024  assert(left > 0);
3025 
3026  est = SCIPconvertRealToInt(scip, relaxedbd);
3027  assert(end >= est);
3028  assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
3029 
3030  /* compute the overlap of the job after the propagation but considering the relaxed bound */
3031  right = MIN(end - est + 1, end - begin);
3032  assert(right > 0);
3033 
3034  /* compute the minimum overlap */
3035  overlap = MIN(left, right);
3036  assert(overlap > 0);
3037  assert(overlap <= end - begin);
3038  assert(overlap <= duration);
3039 
3040  if( usebdwidening )
3041  {
3042  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
3043  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
3044  }
3045  else
3046  {
3047  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
3048  }
3049  }
3050 
3051  /* subtract the amount of energy which is available due to the overlap of the inference start time */
3052  requiredenergy -= (SCIP_Longint) overlap * demand;
3053 
3054  if( explanation != NULL )
3055  explanation[v] = TRUE;
3056 
3057  continue;
3058  }
3059 
3060  /* global time points */
3061  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
3062  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
3063 
3064  glbenergy = 0;
3065 
3066  /* check if the has any overlap w.r.t. global 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  /* evaluated global contribution */
3072  glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
3073 
3074  /* remove the globally available energy form the required energy */
3075  requiredenergy -= glbenergy;
3076 
3077  if( explanation != NULL )
3078  explanation[v] = TRUE;
3079  }
3080 
3081  /* local time points */
3082  est = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
3083  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
3084 
3085  /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3086  * time window
3087  */
3088  if( est + duration > begin && lst < end )
3089  {
3090  overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3091 
3092  /* evaluated additionally local energy contribution */
3093  locenergies[v] = overlaps[v] * demand - glbenergy;
3094  assert(locenergies[v] >= 0);
3095  }
3096  }
3097 
3098  /* sort the variable contributions w.r.t. additional local energy contributions */
3099  SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3100 
3101  /* add local energy contributions until an overload is implied */
3102  for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3103  {
3104  SCIP_VAR* var;
3105  int duration;
3106  int overlap;
3107  int relaxlb;
3108  int relaxub;
3109  int idx;
3110 
3111  idx = idxs[v];
3112  assert(idx >= 0 && idx < nvars);
3113 
3114  var = vars[idx];
3115  assert(var != NULL);
3116  assert(var != infervar);
3117 
3118  duration = durations[idx];
3119  assert(duration > 0);
3120 
3121  overlap = overlaps[v];
3122  assert(overlap > 0);
3123 
3124  requiredenergy -= locenergies[v];
3125 
3126  if( requiredenergy < -1 )
3127  {
3128  int demand;
3129 
3130  demand = demands[idx];
3131  assert(demand > 0);
3132 
3133  overlap += (int)((requiredenergy + 1) / demand);
3134 
3135 #ifndef NDEBUG
3136  requiredenergy += locenergies[v];
3137  requiredenergy -= (SCIP_Longint) overlap * demand;
3138  assert(requiredenergy < 0);
3139 #endif
3140  }
3141  assert(overlap > 0);
3142 
3143  relaxlb = begin - duration + overlap;
3144  relaxub = end - overlap;
3145 
3146  SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3147  SCIPvarGetName(var),
3150  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var),
3151  relaxlb, relaxub, demands[idx], duration);
3152 
3153  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3154  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3155 
3156  if( explanation != NULL )
3157  explanation[idx] = TRUE;
3158  }
3159 
3160  assert(requiredenergy < 0);
3161 
3162  SCIPfreeBufferArray(scip, &idxs);
3163  SCIPfreeBufferArray(scip, &overlaps);
3164  SCIPfreeBufferArray(scip, &locenergies);
3165 
3166  return SCIP_OKAY;
3167 }
3168 
3169 /** resolve propagation w.r.t. the cumulative condition */
3170 static
3172  SCIP* scip, /**< SCIP data structure */
3173  int nvars, /**< number of start time variables (activities) */
3174  SCIP_VAR** vars, /**< array of start time variables */
3175  int* durations, /**< array of durations */
3176  int* demands, /**< array of demands */
3177  int capacity, /**< cumulative capacity */
3178  int hmin, /**< left bound of time axis to be considered (including hmin) */
3179  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3180  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3181  INFERINFO inferinfo, /**< the user information */
3182  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3183  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3184  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3185  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3186  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3187  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3188  )
3189 {
3190  switch( inferInfoGetProprule(inferinfo) )
3191  {
3192  case PROPRULE_1_CORETIMES:
3193  {
3194  int inferdemand;
3195  int inferduration;
3196  int inferpos;
3197  int inferpeak;
3198  int relaxedpeak;
3199  int provedpeak;
3200 
3201  /* get the position of the inferred variable in the vars array */
3202  inferpos = inferInfoGetData1(inferinfo);
3203  if( inferpos >= nvars || vars[inferpos] != infervar )
3204  {
3205  /* find inference variable in constraint */
3206  for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3207  {}
3208  }
3209  assert(inferpos < nvars);
3210  assert(vars[inferpos] == infervar);
3211 
3212  inferdemand = demands[inferpos];
3213  inferduration = durations[inferpos];
3214 
3215  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3216  {
3217  /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3218  * the inference variable
3219  */
3220  assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
3221 
3222  SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3223  SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
3224  SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3225 
3226  /* get the inference peak that the time point which lead to the that propagtion */
3227  inferpeak = inferInfoGetData2(inferinfo);
3228  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3229  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3230  */
3231  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3232  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) + inferduration;
3233 
3234  /* make sure that the relaxed peak is part of the effective horizon */
3235  relaxedpeak = MIN(relaxedpeak, hmax-1);
3236 
3237  /* make sure that relaxed peak is not larger than the infer peak
3238  *
3239  * This can happen in case the variable is not an active variable!
3240  */
3241  relaxedpeak = MAX(relaxedpeak, inferpeak);
3242  assert(relaxedpeak >= inferpeak);
3243  assert(relaxedpeak >= hmin);
3244  }
3245  else
3246  {
3247  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3248 
3249  SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3250  SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
3251  SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3252 
3253  /* get the time interval where the job could not be scheduled */
3254  inferpeak = inferInfoGetData2(inferinfo);
3255  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3256  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3257  */
3258  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3259  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) - 1;
3260 
3261  /* make sure that the relaxed peak is part of the effective horizon */
3262  relaxedpeak = MAX(relaxedpeak, hmin);
3263 
3264  /* make sure that relaxed peak is not larger than the infer peak
3265  *
3266  * This can happen in case the variable is not an active variable!
3267  */
3268  relaxedpeak = MIN(relaxedpeak, inferpeak);
3269  assert(relaxedpeak < hmax);
3270  }
3271 
3272  /* resolves the propagation of the core time algorithm */
3273  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3274  infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3275 
3276  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3277  {
3278  if( usebdwidening )
3279  {
3280  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3281  }
3282  else
3283  {
3284  /* old upper bound of variable itself is part of the explanation */
3285  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3286  }
3287  }
3288  else
3289  {
3290  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3291 
3292  if( usebdwidening )
3293  {
3294  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3295  }
3296  else
3297  {
3298  /* old lower bound of variable itself is part of the explanation */
3299  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3300  }
3301  }
3302 
3303  if( explanation != NULL )
3304  explanation[inferpos] = TRUE;
3305 
3306  break;
3307  }
3309  case PROPRULE_3_TTEF:
3310  {
3311  int begin;
3312  int end;
3313 
3314  begin = inferInfoGetData1(inferinfo);
3315  end = inferInfoGetData2(inferinfo);
3316  assert(begin < end);
3317 
3318  begin = MAX(begin, hmin);
3319  end = MIN(end, hmax);
3320 
3321  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3322  begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3323 
3324  break;
3325  }
3326 
3327  case PROPRULE_0_INVALID:
3328  default:
3329  SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3330  SCIPABORT();
3331  return SCIP_INVALIDDATA; /*lint !e527*/
3332  }
3333 
3334  (*result) = SCIP_SUCCESS;
3335 
3336  return SCIP_OKAY;
3337 }
3338 
3339 /**@} */
3340 
3341 
3342 /**@name Enforcement methods
3343  *
3344  * @{
3345  */
3346 
3347 /** apply all fixings which are given by the alternative bounds */
3348 static
3350  SCIP* scip, /**< SCIP data structure */
3351  SCIP_VAR** vars, /**< array of active variables */
3352  int nvars, /**< number of active variables */
3353  int* alternativelbs, /**< alternative lower bounds */
3354  int* alternativeubs, /**< alternative lower bounds */
3355  int* downlocks, /**< number of constraints with down lock participating by the computation */
3356  int* uplocks, /**< number of constraints with up lock participating by the computation */
3357  SCIP_Bool* branched /**< pointer to store if a branching was applied */
3358  )
3359 {
3360  int v;
3361 
3362  for( v = 0; v < nvars; ++v )
3363  {
3364  SCIP_VAR* var;
3365  SCIP_Real objval;
3366 
3367  var = vars[v];
3368  assert(var != NULL);
3369 
3370  objval = SCIPvarGetObj(var);
3371 
3372  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] && !SCIPisNegative(scip, objval) )
3373  {
3374  int ub;
3375 
3376  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3377 
3378  if( alternativelbs[v] <= ub )
3379  {
3380  SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3381  (*branched) = TRUE;
3382 
3383  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3384  SCIPvarGetLbLocal(var), alternativelbs[v]);
3385 
3386  return SCIP_OKAY;
3387  }
3388  }
3389 
3390  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] && !SCIPisPositive(scip, objval) )
3391  {
3392  int lb;
3393 
3394  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3395 
3396  if( alternativeubs[v] >= lb )
3397  {
3398  SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3399  (*branched) = TRUE;
3400 
3401  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3402  alternativeubs[v], SCIPvarGetUbLocal(var));
3403 
3404  return SCIP_OKAY;
3405  }
3406  }
3407  }
3408 
3409  return SCIP_OKAY;
3410 }
3411 
3412 /** remove the capacity requirments for all job which start at the curtime */
3413 static
3415  SCIP_CONSDATA* consdata, /**< constraint data */
3416  int curtime, /**< current point in time */
3417  int* starttimes, /**< array of start times */
3418  int* startindices, /**< permutation with respect to the start times */
3419  int* freecapacity, /**< pointer to store the resulting free capacity */
3420  int* idx, /**< pointer to index in start time array */
3421  int nvars /**< number of vars in array of starttimes and startindices */
3422  )
3423 {
3424 #if defined SCIP_DEBUG && !defined NDEBUG
3425  int oldidx;
3426 
3427  assert(idx != NULL);
3428  oldidx = *idx;
3429 #else
3430  assert(idx != NULL);
3431 #endif
3432 
3433  assert(starttimes != NULL);
3434  assert(starttimes != NULL);
3435  assert(freecapacity != NULL);
3436  assert(starttimes[*idx] == curtime);
3437  assert(consdata->demands != NULL);
3438  assert(freecapacity != idx);
3439 
3440  /* subtract all capacity needed up to this point */
3441  (*freecapacity) -= consdata->demands[startindices[*idx]];
3442 
3443  while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3444  {
3445  ++(*idx);
3446  (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3447  assert(freecapacity != idx);
3448  }
3449 #ifdef SCIP_DEBUG
3450  assert(oldidx <= *idx);
3451 #endif
3452 }
3453 
3454 /** add the capacity requirments for all job which end at the curtime */
3455 static
3456 void addEndingJobDemands(
3457  SCIP_CONSDATA* consdata, /**< constraint data */
3458  int curtime, /**< current point in time */
3459  int* endtimes, /**< array of end times */
3460  int* endindices, /**< permutation with rspect to the end times */
3461  int* freecapacity, /**< pointer to store the resulting free capacity */
3462  int* idx, /**< pointer to index in end time array */
3463  int nvars /**< number of vars in array of starttimes and startindices */
3464  )
3465 {
3466 #if defined SCIP_DEBUG && !defined NDEBUG
3467  int oldidx;
3468  oldidx = *idx;
3469 #endif
3470 
3471  /* free all capacity usages of jobs the are no longer running */
3472  while( endtimes[*idx] <= curtime && *idx < nvars)
3473  {
3474  (*freecapacity) += consdata->demands[endindices[*idx]];
3475  ++(*idx);
3476  }
3477 
3478 #ifdef SCIP_DEBUG
3479  assert(oldidx <= *idx);
3480 #endif
3481 }
3482 
3483 /** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3484 static
3486  SCIP* scip, /**< SCIP data structure */
3487  SCIP_CONSDATA* consdata, /**< constraint handler data */
3488  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3489  int* timepoint /**< pointer to store the time point of the peak */
3490  )
3491 {
3492  int* starttimes; /* stores when each job is starting */
3493  int* endtimes; /* stores when each job ends */
3494  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3495  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3496 
3497  int nvars; /* number of activities for this constraint */
3498  int freecapacity; /* remaining capacity */
3499  int curtime; /* point in time which we are just checking */
3500  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3501 
3502  int hmin;
3503  int hmax;
3504 
3505  int j;
3506 
3507  assert(consdata != NULL);
3508 
3509  nvars = consdata->nvars;
3510  assert(nvars > 0);
3511 
3512  *timepoint = consdata->hmax;
3513 
3514  assert(consdata->vars != NULL);
3515 
3516  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3517  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3518  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3519  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3520 
3521  /* create event point arrays */
3522  createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3523  starttimes, endtimes, startindices, endindices);
3524 
3525  endindex = 0;
3526  freecapacity = consdata->capacity;
3527  hmin = consdata->hmin;
3528  hmax = consdata->hmax;
3529 
3530  /* check each startpoint of a job whether the capacity is kept or not */
3531  for( j = 0; j < nvars; ++j )
3532  {
3533  curtime = starttimes[j];
3534  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3535 
3536  if( curtime >= hmax )
3537  break;
3538 
3539  /* remove the capacity requirments for all job which start at the curtime */
3540  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3541 
3542  /* add the capacity requirments for all job which end at the curtime */
3543  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3544 
3545  assert(freecapacity <= consdata->capacity);
3546  assert(endindex <= nvars);
3547 
3548  /* endindex - points to the next job which will finish */
3549  /* j - points to the last job that has been released */
3550 
3551  /* if free capacity is smaller than zero, then add branching candidates */
3552  if( freecapacity < 0 && curtime >= hmin )
3553  {
3554  *timepoint = curtime;
3555  break;
3556  }
3557  } /*lint --e{850}*/
3558 
3559  /* free all buffer arrays */
3560  SCIPfreeBufferArray(scip, &endindices);
3561  SCIPfreeBufferArray(scip, &startindices);
3562  SCIPfreeBufferArray(scip, &endtimes);
3563  SCIPfreeBufferArray(scip, &starttimes);
3564 
3565  return SCIP_OKAY;
3566 }
3567 
3568 /** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3569 static
3571  SCIP* scip, /**< SCIP data structure */
3572  SCIP_CONS** conss, /**< constraints to be processed */
3573  int nconss, /**< number of constraints */
3574  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3575  int* nbranchcands /**< pointer to store the number of branching variables */
3576  )
3577 {
3578  SCIP_HASHTABLE* collectedvars;
3579  int c;
3580 
3581  assert(scip != NULL);
3582  assert(conss != NULL);
3583 
3584  /* create a hash table */
3585  SCIP_CALL( SCIPhashtableCreate(&collectedvars, SCIPblkmem(scip), SCIPgetNVars(scip),
3586  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3587 
3588  assert(scip != NULL);
3589  assert(conss != NULL);
3590 
3591  for( c = 0; c < nconss; ++c )
3592  {
3593  SCIP_CONS* cons;
3594  SCIP_CONSDATA* consdata;
3595 
3596  int curtime;
3597  int j;
3598 
3599  cons = conss[c];
3600  assert(cons != NULL);
3601 
3602  if( !SCIPconsIsActive(cons) )
3603  continue;
3604 
3605  consdata = SCIPconsGetData(cons);
3606  assert(consdata != NULL);
3607 
3608  /* get point in time when capacity is exceeded */
3609  SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3610 
3611  if( curtime < consdata->hmin || curtime >= consdata->hmax )
3612  continue;
3613 
3614  /* report all variables that are running at that point in time */
3615  for( j = 0; j < consdata->nvars; ++j )
3616  {
3617  SCIP_VAR* var;
3618  int lb;
3619  int ub;
3620 
3621  var = consdata->vars[j];
3622  assert(var != NULL);
3623 
3624  /* check if the variable was already added */
3625  if( SCIPhashtableExists(collectedvars, (void*)var) )
3626  continue;
3627 
3628  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3629  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3630 
3631  if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3632  {
3633  SCIP_Real solval;
3634  SCIP_Real score;
3635 
3636  solval = SCIPgetSolVal(scip, sol, var);
3637  score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3638 
3639  SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3640  SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3641  (*nbranchcands)++;
3642 
3643  SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3644  }
3645  }
3646  }
3647 
3648  SCIPhashtableFree(&collectedvars);
3649 
3650  SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3651 
3652  return SCIP_OKAY;
3653 }
3654 
3655 /** enforcement of an LP, pseudo, or relaxation solution */
3656 static
3658  SCIP* scip, /**< SCIP data structure */
3659  SCIP_CONS** conss, /**< constraints to be processed */
3660  int nconss, /**< number of constraints */
3661  SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
3662  SCIP_Bool branch, /**< should branching candidates be collected */
3663  SCIP_RESULT* result /**< pointer to store the result */
3664  )
3665 {
3666  if( branch )
3667  {
3668  int nbranchcands;
3669 
3670  nbranchcands = 0;
3671  SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3672 
3673  if( nbranchcands > 0 )
3674  (*result) = SCIP_INFEASIBLE;
3675  }
3676  else
3677  {
3678  SCIP_Bool violated;
3679  int c;
3680 
3681  violated = FALSE;
3682 
3683  /* first check if a constraints is violated */
3684  for( c = 0; c < nconss && !violated; ++c )
3685  {
3686  SCIP_CONS* cons;
3687 
3688  cons = conss[c];
3689  assert(cons != NULL);
3690 
3691  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3692  }
3693 
3694  if( violated )
3695  (*result) = SCIP_INFEASIBLE;
3696  }
3697 
3698  return SCIP_OKAY;
3699 }
3700 
3701 /**@} */
3702 
3703 /**@name Propagation
3704  *
3705  * @{
3706  */
3707 
3708 /** check if cumulative constraint is independently of all other constraints */
3709 static
3711  SCIP_CONS* cons /**< cumulative constraint */
3712  )
3713 {
3714  SCIP_CONSDATA* consdata;
3715  SCIP_VAR** vars;
3716  SCIP_Bool* downlocks;
3717  SCIP_Bool* uplocks;
3718  int nvars;
3719  int v;
3720 
3721  consdata = SCIPconsGetData(cons);
3722  assert(consdata != NULL);
3723 
3724  nvars = consdata->nvars;
3725  vars = consdata->vars;
3726  downlocks = consdata->downlocks;
3727  uplocks = consdata->uplocks;
3728 
3729  /* check if the cumulative constraint has the only locks on the involved variables */
3730  for( v = 0; v < nvars; ++v )
3731  {
3732  SCIP_VAR* var;
3733 
3734  var = vars[v];
3735  assert(var != NULL);
3736 
3737  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
3738  || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
3739  return FALSE;
3740  }
3741 
3742  return TRUE;
3743 }
3744 
3745 /** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3746  * (dual reductions)
3747  */
3748 static
3750  SCIP* scip, /**< SCIP data structure */
3751  SCIP_CONS* cons, /**< cumulative constraint */
3752  SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3753  int* nchgbds, /**< pointer to store the number changed variable bounds */
3754  int* nfixedvars, /**< pointer to count number of fixings */
3755  int* ndelconss, /**< pointer to count number of deleted constraints */
3756  SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3757  SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3758  )
3759 {
3760  SCIP_CONSDATA* consdata;
3761  SCIP_VAR** vars;
3762  SCIP_Real* objvals;
3763  SCIP_Real* lbs;
3764  SCIP_Real* ubs;
3765  SCIP_Real timelimit;
3766  SCIP_Real memorylimit;
3767  SCIP_Bool solved;
3768  SCIP_Bool error;
3769 
3770  int ncheckconss;
3771  int nvars;
3772  int v;
3773 
3774  assert(scip != NULL);
3775  assert(!SCIPconsIsModifiable(cons));
3776  assert(SCIPgetNConss(scip) > 0);
3777 
3778  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3779  * would/could end in an implication which can lead to cutoff of the/all optimal solution
3780  */
3781  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
3782  return SCIP_OKAY;
3783 
3784  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3785  * use the locks to decide for a dual reduction using this constraint;
3786  */
3787  if( !SCIPconsIsChecked(cons) )
3788  return SCIP_OKAY;
3789 
3790  ncheckconss = SCIPgetNCheckConss(scip);
3791 
3792  /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3793  * presolved problem do nothing execpt to change the parameter settings
3794  */
3795  if( ncheckconss == 1 )
3796  {
3797  /* shrink the minimal maximum value for the conflict length */
3798  SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3799 
3800  /* use only first unique implication point */
3801  SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3802 
3803  /* do not use reconversion conflicts */
3804  SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3805 
3806  /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3807  SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3808 
3809  /* increase the number of conflicts which induce a restart */
3810  SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3811 
3812  /* weight the variable which made into a conflict */
3813  SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3814 
3815  /* do not check pseudo solution (for performance reasons) */
3816  SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3817 
3818  /* use value based history to detect a reasonable branching point */
3819  SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3820 
3821  /* turn of LP relaxation */
3822  SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3823 
3824  /* prefer the down branch in case the value based history does not suggest something */
3825  SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3826 
3827  /* accept any bound change */
3828  SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3829 
3830  /* allow for at most 10 restart, after that the value based history should be reliable */
3831  SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3832 
3833  /* set priority for depth first search to highest possible value */
3834  SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3835 
3836  return SCIP_OKAY;
3837  }
3838 
3839  consdata = SCIPconsGetData(cons);
3840  assert(consdata != NULL);
3841 
3842  /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3843  * fail on the first place
3844  */
3845  if( consdata->triedsolving )
3846  return SCIP_OKAY;
3847 
3848  /* check if constraint is independently */
3849  if( !isConsIndependently(cons) )
3850  return SCIP_OKAY;
3851 
3852  /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3853  * constraint is deleted; otherwise, we want to ensure that we do not try that again
3854  */
3855  consdata->triedsolving = TRUE;
3856 
3857  SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3858  SCIPconsGetName(cons), SCIPgetNVars(scip), SCIPgetNConss(scip));
3859  SCIPdebugPrintCons(scip, cons, NULL);
3860 
3861  nvars = consdata->nvars;
3862  vars = consdata->vars;
3863 
3864  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3865  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3866  SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3867 
3868  for( v = 0; v < nvars; ++v )
3869  {
3870  SCIP_VAR* var;
3871 
3872  /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3873  * array
3874  */
3875  var = vars[v];
3876  assert(var != NULL);
3877 
3878  lbs[v] = SCIPvarGetLbLocal(var);
3879  ubs[v] = SCIPvarGetUbLocal(var);
3880 
3881  objvals[v] = SCIPvarGetObj(var);
3882  }
3883 
3884  /* check whether there is enough time and memory left */
3885  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3886  if( !SCIPisInfinity(scip, timelimit) )
3887  timelimit -= SCIPgetSolvingTime(scip);
3888  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3889 
3890  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3891  if( !SCIPisInfinity(scip, memorylimit) )
3892  {
3893  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3894  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3895  }
3896 
3897  /* solve the cumulative condition separately */
3898  SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3899  consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3900 
3901  if( !(*cutoff) && !(*unbounded) && !error )
3902  {
3903  SCIP_Bool infeasible;
3904  SCIP_Bool tightened;
3905  SCIP_Bool allfixed;
3906 
3907  allfixed = TRUE;
3908 
3909  for( v = 0; v < nvars; ++v )
3910  {
3911  /* check if variable is fixed */
3912  if( lbs[v] + 0.5 > ubs[v] )
3913  {
3914  SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3915  assert(!infeasible);
3916 
3917  if( tightened )
3918  {
3919  (*nfixedvars)++;
3920  consdata->triedsolving = FALSE;
3921  }
3922  }
3923  else
3924  {
3925  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3926  assert(!infeasible);
3927 
3928  if( tightened )
3929  {
3930  (*nchgbds)++;
3931  consdata->triedsolving = FALSE;
3932  }
3933 
3934  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3935  assert(!infeasible);
3936 
3937  if( tightened )
3938  {
3939  (*nchgbds)++;
3940  consdata->triedsolving = FALSE;
3941  }
3942 
3943  allfixed = FALSE;
3944  }
3945  }
3946 
3947  /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3948  if( allfixed )
3949  {
3950  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3951  (*ndelconss)++;
3952  }
3953  }
3954 
3955  SCIPfreeBufferArray(scip, &objvals);
3956  SCIPfreeBufferArray(scip, &ubs);
3957  SCIPfreeBufferArray(scip, &lbs);
3958 
3959  return SCIP_OKAY;
3960 }
3961 
3962 /** start conflict analysis to analysis the core insertion which is infeasible */
3963 static
3965  SCIP* scip, /**< SCIP data structure */
3966  int nvars, /**< number of start time variables (activities) */
3967  SCIP_VAR** vars, /**< array of start time variables */
3968  int* durations, /**< array of durations */
3969  int* demands, /**< array of demands */
3970  int capacity, /**< cumulative capacity */
3971  int hmin, /**< left bound of time axis to be considered (including hmin) */
3972  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3973  SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3974  int inferduration, /**< duration of the start time variable */
3975  int inferdemand, /**< demand of the start time variable */
3976  int inferpeak, /**< profile preak which causes the infeasibilty */
3977  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3978  SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3979  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3980  )
3981 {
3982  SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3983  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3984  SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3985 
3986  /* initialize conflict analysis if conflict analysis is applicable */
3988  {
3990 
3991  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3992  infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3993 
3994  SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3995 
3996  /* add both bound of the inference variable since these biuld the core which we could not inserted */
3997  if( usebdwidening )
3998  {
3999  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
4000  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
4001  }
4002  else
4003  {
4004  SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
4005  SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
4006  }
4007 
4008  *initialized = TRUE;
4009  }
4010 
4011  return SCIP_OKAY;
4012 }
4013 
4014 /** We are using the core resource profile which contains all core except the one of the start time variable which we
4015  * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
4016  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4017  * analysis
4018  */
4019 static
4021  SCIP* scip, /**< SCIP data structure */
4022  int nvars, /**< number of start time variables (activities) */
4023  SCIP_VAR** vars, /**< array of start time variables */
4024  int* durations, /**< array of durations */
4025  int* demands, /**< array of demands */
4026  int capacity, /**< cumulative capacity */
4027  int hmin, /**< left bound of time axis to be considered (including hmin) */
4028  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4029  SCIP_CONS* cons, /**< constraint which is propagated */
4030  SCIP_PROFILE* profile, /**< resource profile */
4031  int idx, /**< position of the variable to propagate */
4032  int* nchgbds, /**< pointer to store the number of bound changes */
4033  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
4034  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4035  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4036  SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
4037  )
4038 {
4039  SCIP_VAR* var;
4040  int ntimepoints;
4041  int duration;
4042  int demand;
4043  int peak;
4044  int newlb;
4045  int est;
4046  int lst;
4047  int pos;
4048 
4049  var = vars[idx];
4050  assert(var != NULL);
4051 
4052  duration = durations[idx];
4053  assert(duration > 0);
4054 
4055  demand = demands[idx];
4056  assert(demand > 0);
4057 
4058  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4059  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4060  ntimepoints = SCIPprofileGetNTimepoints(profile);
4061 
4062  /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
4063  * load which we have at the earliest start time (lower bound)
4064  */
4065  (void) SCIPprofileFindLeft(profile, est, &pos);
4066 
4067  SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
4068 
4069  /* we now trying to move the earliest start time in steps of at most "duration" length */
4070  do
4071  {
4072  INFERINFO inferinfo;
4073  SCIP_Bool tightened;
4074  int ect;
4075 
4076 #ifndef NDEBUG
4077  {
4078  /* in debug mode we check that we adjust the search position correctly */
4079  int tmppos;
4080 
4081  (void)SCIPprofileFindLeft(profile, est, &tmppos);
4082  assert(pos == tmppos);
4083  }
4084 #endif
4085  ect = est + duration;
4086  peak = -1;
4087 
4088  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4089  * want a peak which is closest to the earliest completion time
4090  */
4091  do
4092  {
4093  /* check if the profile load conflicts with the demand of the start time variable */
4094  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4095  peak = pos;
4096 
4097  pos++;
4098  }
4099  while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4100 
4101  /* if we found no peak that means current the job could be scheduled at its earliest start time without
4102  * conflicting to the core resource profile
4103  */
4104  /* coverity[check_after_sink] */
4105  if( peak == -1 )
4106  break;
4107 
4108  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4109  * profile. That means we have to move it to the next time point in the resource profile but at most to the
4110  * earliest completion time (the remaining move will done in the next loop)
4111  */
4112  newlb = SCIPprofileGetTime(profile, peak+1);
4113  newlb = MIN(newlb, ect);
4114 
4115  /* if the earliest start time is greater than the lst we detected an infeasibilty */
4116  if( newlb > lst )
4117  {
4118  SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4119 
4120  /* use conflict analysis to analysis the core insertion which was infeasible */
4121  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4122  var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4123 
4124  if( explanation != NULL )
4125  explanation[idx] = TRUE;
4126 
4127  *infeasible = TRUE;
4128 
4129  break;
4130  }
4131 
4132  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4133  * bound change
4134  */
4135  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4136 
4137  /* perform the bound lower bound change */
4138  if( inferInfoIsValid(inferinfo) )
4139  {
4140  SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4141  }
4142  else
4143  {
4144  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)newlb, TRUE, infeasible, &tightened) );
4145  }
4146  assert(tightened);
4147  assert(!(*infeasible));
4148 
4149  SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4150  (*nchgbds)++;
4151 
4152  /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4154 
4155  /* adjust the earliest start time
4156  *
4157  * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4158  * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4159  * involved.
4160  */
4161  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4162  assert(est >= newlb);
4163 
4164  /* adjust the search position for the resource profile for the next step */
4165  if( est == SCIPprofileGetTime(profile, peak+1) )
4166  pos = peak + 1;
4167  else
4168  pos = peak;
4169  }
4170  while( est < lst );
4171 
4172  return SCIP_OKAY;
4173 }
4174 
4175 /** We are using the core resource profile which contains all core except the one of the start time variable which we
4176  * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4177  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4178  * analysis
4179  */
4180 static
4182  SCIP* scip, /**< SCIP data structure */
4183  SCIP_VAR* var, /**< start time variable to propagate */
4184  int duration, /**< duration of the job */
4185  int demand, /**< demand of the job */
4186  int capacity, /**< cumulative capacity */
4187  SCIP_CONS* cons, /**< constraint which is propagated */
4188  SCIP_PROFILE* profile, /**< resource profile */
4189  int idx, /**< position of the variable to propagate */
4190  int* nchgbds /**< pointer to store the number of bound changes */
4191  )
4192 {
4193  int ntimepoints;
4194  int newub;
4195  int peak;
4196  int pos;
4197  int est;
4198  int lst;
4199  int lct;
4200 
4201  assert(var != NULL);
4202  assert(duration > 0);
4203  assert(demand > 0);
4204 
4205  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4206  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4207 
4208  /* in case the start time variable is fixed do nothing */
4209  if( est == lst )
4210  return SCIP_OKAY;
4211 
4212  ntimepoints = SCIPprofileGetNTimepoints(profile);
4213 
4214  lct = lst + duration;
4215 
4216  /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4217  * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4218  * position gives us the load which we have at the latest completion time minus one
4219  */
4220  (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4221 
4222  SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4223  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
4224 
4225  if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4226  return SCIP_OKAY;
4227 
4228  /* we now trying to move the latest start time in steps of at most "duration" length */
4229  do
4230  {
4231  INFERINFO inferinfo;
4232  SCIP_Bool tightened;
4233  SCIP_Bool infeasible;
4234 
4235  peak = -1;
4236 
4237 #ifndef NDEBUG
4238  {
4239  /* in debug mode we check that we adjust the search position correctly */
4240  int tmppos;
4241 
4242  (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4243  assert(pos == tmppos);
4244  }
4245 #endif
4246 
4247  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4248  * want a peak which is closest to the latest start time
4249  */
4250  do
4251  {
4252  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4253  peak = pos;
4254 
4255  pos--;
4256  }
4257  while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4258 
4259  /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4260  * to the core resource profile
4261  */
4262  /* coverity[check_after_sink] */
4263  if( peak == -1 )
4264  break;
4265 
4266  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4267  * profile. That means the job has be done until that point. Hence that gives us the latest completion
4268  * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4269  * doing in the next loop)
4270  */
4271  newub = SCIPprofileGetTime(profile, peak);
4272  newub = MAX(newub, lst) - duration;
4273  assert(newub >= est);
4274 
4275  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4276  * bound change
4277  */
4278  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4279 
4280  /* perform the bound upper bound change */
4281  if( inferInfoIsValid(inferinfo) )
4282  {
4283  SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4284  }
4285  else
4286  {
4287  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)newub, TRUE, &infeasible, &tightened) );
4288  }
4289  assert(tightened);
4290  assert(!infeasible);
4291 
4292  SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4293  (*nchgbds)++;
4294 
4295  /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4297 
4298  /* adjust the latest start and completion time
4299  *
4300  * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4301  * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4302  * involved.
4303  */
4304  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4305  assert(lst <= newub);
4306  lct = lst + duration;
4307 
4308  /* adjust the search position for the resource profile for the next step */
4309  if( SCIPprofileGetTime(profile, peak) == lct )
4310  pos = peak - 1;
4311  else
4312  pos = peak;
4313  }
4314  while( est < lst );
4315 
4316  return SCIP_OKAY;
4317 }
4318 
4319 /** compute for the different earliest start and latest completion time the core energy of the corresponding time
4320  * points
4321  */
4322 static
4324  SCIP_PROFILE* profile, /**< core profile */
4325  int nvars, /**< number of start time variables (activities) */
4326  int* ests, /**< array of sorted earliest start times */
4327  int* lcts, /**< array of sorted latest completion times */
4328  int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4329  int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4330  )
4331 {
4332  int ntimepoints;
4333  int energy;
4334  int t;
4335  int v;
4336 
4337  ntimepoints = SCIPprofileGetNTimepoints(profile);
4338  t = ntimepoints - 1;
4339  energy = 0;
4340 
4341  /* compute core energy after the earliest start time of each job */
4342  for( v = nvars-1; v >= 0; --v )
4343  {
4344  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4345  {
4346  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4347  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4348  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4349  t--;
4350  }
4351  assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4352 
4353  /* maybe ests[j] is in-between two timepoints */
4354  if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4355  {
4356  assert(t > 0);
4357  coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4358  }
4359  else
4360  coreEnergyAfterEst[v] = energy;
4361  }
4362 
4363  t = ntimepoints - 1;
4364  energy = 0;
4365 
4366  /* compute core energy after the latest completion time of each job */
4367  for( v = nvars-1; v >= 0; --v )
4368  {
4369  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4370  {
4371  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4372  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4373  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4374  t--;
4375  }
4376  assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4377 
4378  /* maybe lcts[j] is in-between two timepoints */
4379  if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4380  {
4381  assert(t > 0);
4382  coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4383  }
4384  else
4385  coreEnergyAfterLct[v] = energy;
4386  }
4387 }
4388 
4389 /** collect earliest start times, latest completion time, and free energy contributions */
4390 static
4391 void collectDataTTEF(
4392  SCIP* scip, /**< SCIP data structure */
4393  int nvars, /**< number of start time variables (activities) */
4394  SCIP_VAR** vars, /**< array of start time variables */
4395  int* durations, /**< array of durations */
4396  int* demands, /**< array of demands */
4397  int hmin, /**< left bound of time axis to be considered (including hmin) */
4398  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4399  int* permests, /**< array to store the variable positions */
4400  int* ests, /**< array to store earliest start times */
4401  int* permlcts, /**< array to store the variable positions */
4402  int* lcts, /**< array to store latest completion times */
4403  int* ects, /**< array to store earliest completion times of the flexible part of the job */
4404  int* lsts, /**< array to store latest start times of the flexible part of the job */
4405  int* flexenergies /**< array to store the flexible energies of each job */
4406  )
4407 {
4408  int v;
4409 
4410  for( v = 0; v < nvars; ++ v)
4411  {
4412  int duration;
4413  int leftadjust;
4414  int rightadjust;
4415  int core;
4416  int est;
4417  int lct;
4418  int ect;
4419  int lst;
4420 
4421  duration = durations[v];
4422  assert(duration > 0);
4423 
4424  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4425  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
4426  ect = est + duration;
4427  lct = lst + duration;
4428 
4429  ests[v] = est;
4430  lcts[v] = lct;
4431  permests[v] = v;
4432  permlcts[v] = v;
4433 
4434  /* compute core time window which lies within the effective horizon */
4435  core = (int) computeCoreWithInterval(hmin, hmax, ect, lst);
4436 
4437  /* compute the number of time steps the job could run before the effective horizon */
4438  leftadjust = MAX(0, hmin - est);
4439 
4440  /* compute the number of time steps the job could run after the effective horizon */
4441  rightadjust = MAX(0, lct - hmax);
4442 
4443  /* compute for each job the energy which is flexible; meaning not part of the core */
4444  flexenergies[v] = duration - leftadjust - rightadjust - core;
4445  flexenergies[v] = MAX(0, flexenergies[v]);
4446  flexenergies[v] *= demands[v];
4447  assert(flexenergies[v] >= 0);
4448 
4449  /* the earliest completion time of the flexible energy */
4450  ects[v] = MIN(ect, lst);
4451 
4452  /* the latest start time of the flexible energy */
4453  lsts[v] = MAX(ect, lst);
4454  }
4455 }
4456 
4457 /** try to tighten the lower bound of the given variable */
4458 static
4460  SCIP* scip, /**< SCIP data structure */
4461  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4462  int nvars, /**< number of start time variables (activities) */
4463  SCIP_VAR** vars, /**< array of start time variables */
4464  int* durations, /**< array of durations */
4465  int* demands, /**< array of demands */
4466  int capacity, /**< cumulative capacity */
4467  int hmin, /**< left bound of time axis to be considered (including hmin) */
4468  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4469  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4470  int duration, /**< duration of the job */
4471  int demand, /**< demand of the job */
4472  int est, /**< earliest start time of the job */
4473  int ect, /**< earliest completion time of the flexible part of the job */
4474  int lct, /**< latest completion time of the job */
4475  int begin, /**< begin of the time window under investigation */
4476  int end, /**< end of the time window under investigation */
4477  SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4478  int* bestlb, /**< pointer to strope the best lower bound change */
4479  int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4480  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4481  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4482  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4483  )
4484 {
4485  int newlb;
4486 
4487  assert(begin >= hmin);
4488  assert(end <= hmax);
4489 
4490  /* check if the time-table edge-finding should infer bounds */
4491  if( !conshdlrdata->ttefinfer )
4492  return SCIP_OKAY;
4493 
4494  /* if the job can be processed completely before or after the time window, nothing can be tightened */
4495  if( est >= end || ect <= begin )
4496  return SCIP_OKAY;
4497 
4498  /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4499  * skip since the overload check will do the job
4500  */
4501  if( est >= begin && ect <= end )
4502  return SCIP_OKAY;
4503 
4504  /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4505  * earliest start time
4506  */
4507  if( energy >= demand * ((SCIP_Longint) MAX(begin, est) - MIN(end, ect)) )
4508  return SCIP_OKAY;
4509 
4510  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4511  * present; therefore, we need to add the core;
4512  *
4513  * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4514  * compute the earliest completion time of the (whole) job
4515  */
4516  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4517 
4518  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4519  *
4520  * @note we can round down the compute duration w.r.t. the available energy
4521  */
4522  newlb = end - (int) (energy / demand);
4523 
4524  /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4525  * bound (latest start time); meaning it is not possible to schedule the job
4526  */
4527  if( newlb > lct - duration )
4528  {
4529  /* initialize conflict analysis if conflict analysis is applicable */
4531  {
4532  SCIP_Real relaxedbd;
4533 
4534  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4535 
4536  /* it is enough to overshoot the upper bound of the variable by one */
4537  relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4538 
4539  /* initialize conflict analysis */
4541 
4542  /* added to upper bound (which was overcut be new lower bound) of the variable */
4543  SCIP_CALL( SCIPaddConflictUb(scip, var, NULL) );
4544 
4545  /* analyze the infeasible */
4546  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4547  begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4548 
4549  (*initialized) = TRUE;
4550  }
4551 
4552  (*cutoff) = TRUE;
4553  }
4554  else if( newlb > (*bestlb) )
4555  {
4556  INFERINFO inferinfo;
4557 
4558  assert(newlb > begin);
4559 
4560  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4561 
4562  /* construct inference information */
4563  (*inferinfos) = inferInfoToInt(inferinfo);
4564  (*bestlb) = newlb;
4565  }
4566 
4567  return SCIP_OKAY;
4568 }
4569 
4570 /** try to tighten the upper bound of the given variable */
4571 static
4573  SCIP* scip, /**< SCIP data structure */
4574  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4575  int nvars, /**< number of start time variables (activities) */
4576  SCIP_VAR** vars, /**< array of start time variables */
4577  int* durations, /**< array of durations */
4578  int* demands, /**< array of demands */
4579  int capacity, /**< cumulative capacity */
4580  int hmin, /**< left bound of time axis to be considered (including hmin) */
4581  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4582  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4583  int duration, /**< duration of the job */
4584  int demand, /**< demand of the job */
4585  int est, /**< earliest start time of the job */
4586  int lst, /**< latest start time of the flexible part of the job */
4587  int lct, /**< latest completion time of the job */
4588  int begin, /**< begin of the time window under investigation */
4589  int end, /**< end of the time window under investigation */
4590  SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4591  int* bestub, /**< pointer to strope the best upper bound change */
4592  int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4593  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4594  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4595  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4596  )
4597 {
4598  int newub;
4599 
4600  assert(begin >= hmin);
4601  assert(end <= hmax);
4602  assert(est < begin);
4603 
4604  /* check if the time-table edge-finding should infer bounds */
4605  if( !conshdlrdata->ttefinfer )
4606  return SCIP_OKAY;
4607 
4608  /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4609  if( lst >= end || lct <= begin )
4610  return SCIP_OKAY;
4611 
4612  /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4613  * skip since the overload check will do the job
4614  */
4615  if( lst >= begin && lct <= end )
4616  return SCIP_OKAY;
4617 
4618  /* check if the available energy in the time window is to small to handle the flexible part of the job */
4619  if( energy >= demand * ((SCIP_Longint) MIN(end, lct) - MAX(begin, lst)) )
4620  return SCIP_OKAY;
4621 
4622  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4623  * present; therefore, we need to add the core;
4624  *
4625  * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4626  * latest start of the (whole) job
4627  */
4628  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4629  assert(energy >= 0);
4630 
4631  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4632  *
4633  * @note we can round down the compute duration w.r.t. the available energy
4634  */
4635  assert(demand > 0);
4636  newub = begin - duration + (int) (energy / demand);
4637 
4638  /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4639  * bound (earliest start time); meaning it is not possible to schedule the job
4640  */
4641  if( newub < est )
4642  {
4643  /* initialize conflict analysis if conflict analysis is applicable */
4645  {
4646  SCIP_Real relaxedbd;
4647 
4648  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4649 
4650  /* it is enough to undershoot the lower bound of the variable by one */
4651  relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4652 
4653  /* initialize conflict analysis */
4655 
4656  /* added to lower bound (which was undercut be new upper bound) of the variable */
4657  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
4658 
4659  /* analyze the infeasible */
4660  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4661  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4662 
4663  (*initialized) = TRUE;
4664  }
4665 
4666  (*cutoff) = TRUE;
4667  }
4668  else if( newub < (*bestub) )
4669  {
4670  INFERINFO inferinfo;
4671 
4672  assert(newub < begin);
4673 
4674  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4675 
4676  /* construct inference information */
4677  (*inferinfos) = inferInfoToInt(inferinfo);
4678  (*bestub) = newub;
4679  }
4680 
4681  return SCIP_OKAY;
4682 }
4683 
4684 /** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4685 static
4687  SCIP* scip, /**< SCIP data structure */
4688  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4689  int nvars, /**< number of start time variables (activities) */
4690  SCIP_VAR** vars, /**< array of start time variables */
4691  int* durations, /**< array of durations */
4692  int* demands, /**< array of demands */
4693  int capacity, /**< cumulative capacity */
4694  int hmin, /**< left bound of time axis to be considered (including hmin) */
4695  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4696  int* newlbs, /**< array to buffer new lower bounds */
4697  int* newubs, /**< array to buffer new upper bounds */
4698  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4699  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4700  int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4701  int* flexenergies, /**< array of flexible energies in the same order as the variables */
4702  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4703  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4704  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4705  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4706  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4707  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4708  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4709  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4710  )
4711 {
4712  int coreEnergyAfterEnd;
4713  SCIP_Longint maxavailable;
4714  SCIP_Longint minavailable;
4715  SCIP_Longint totalenergy;
4716  int nests;
4717  int est;
4718  int lct;
4719  int start;
4720  int end;
4721  int v;
4722 
4723  est = INT_MAX;
4724  lct = INT_MIN;
4725 
4726  /* compute earliest start and latest completion time of all jobs */
4727  for( v = 0; v < nvars; ++v )
4728  {
4729  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4730  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4731 
4732  est = MIN(est, start);
4733  lct = MAX(lct, end);
4734  }
4735 
4736  /* adjust the effective time horizon */
4737  hmin = MAX(hmin, est);
4738  hmax = MIN(hmax, lct);
4739 
4740  end = hmax + 1;
4741  coreEnergyAfterEnd = -1;
4742 
4743  maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
4744  minavailable = maxavailable;
4745  totalenergy = computeTotalEnergy(durations, demands, nvars);
4746 
4747  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4748  if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4749  return SCIP_OKAY;
4750 
4751  nests = nvars;
4752 
4753  /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4754  * times define the end of the time interval under investigation
4755  */
4756  for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4757  {
4758  int flexenergy;
4759  int minbegin;
4760  int lbenergy;
4761  int lbcand;
4762  int i;
4763 
4764  lct = lcts[v];
4765 
4766  /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4767  * infinity capacity is available; hence we skip that
4768  */
4769  if( lct > hmax )
4770  continue;
4771 
4772  /* if the latest completion time is smaller then hmin we have to stop */
4773  if( lct <= hmin )
4774  {
4775  assert(v == 0 || lcts[v-1] <= lcts[v]);
4776  break;
4777  }
4778 
4779  /* if the latest completion time equals to previous end time, we can continue since this particular interval
4780  * induced by end was just analyzed
4781  */
4782  if( lct == end )
4783  continue;
4784 
4785  assert(lct < end);
4786 
4787  /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4788  * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4789  * free energy; if so it means that in the next iterate the free-energy cannot be negative
4790  */
4791  if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4792  {
4793  SCIP_Longint freeenergy;
4794 
4795  assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4796  assert(coreEnergyAfterEnd >= 0);
4797 
4798  /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4799  freeenergy = capacity * ((SCIP_Longint) end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4800 
4801  if( freeenergy <= minavailable )
4802  {
4803  SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%" SCIP_LONGINT_FORMAT ">, free energy <%" SCIP_LONGINT_FORMAT ">)\n", lct, minavailable, freeenergy);
4804  continue;
4805  }
4806  }
4807 
4808  SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4809 
4810  end = lct;
4811  coreEnergyAfterEnd = coreEnergyAfterLct[v];
4812 
4813  flexenergy = 0;
4814  minavailable = maxavailable;
4815  minbegin = hmax;
4816  lbcand = -1;
4817  lbenergy = 0;
4818 
4819  /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4820  * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4821  * wider
4822  */
4823  for( i = nests-1; i >= 0; --i )
4824  {
4825  SCIP_VAR* var;
4826  SCIP_Longint freeenergy;
4827  int duration;
4828  int demand;
4829  int begin;
4830  int idx;
4831  int lst;
4832 
4833  idx = perm[i];
4834  assert(idx >= 0);
4835  assert(idx < nvars);
4836  assert(!(*cutoff));
4837 
4838  /* the earliest start time of the job */
4839  est = ests[i];
4840 
4841  /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4842  * latest completion times (which define end) are scant in non-increasing order
4843  */
4844  if( end <= est )
4845  {
4846  nests--;
4847  continue;
4848  }
4849 
4850  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4851  * current ending time
4852  */
4853  if( ((SCIP_Longint) end - est) * capacity >= totalenergy )
4854  break;
4855 
4856  var = vars[idx];
4857  assert(var != NULL);
4858 
4859  duration = durations[idx];
4860  assert(duration > 0);
4861 
4862  demand = demands[idx];
4863  assert(demand > 0);
4864 
4865  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4866 
4867  /* the latest start time of the free part of the job */
4868  lst = lsts[idx];
4869 
4870  /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4871  * investigation; hence the overload check will do the the job
4872  */
4873  assert(est <= minbegin);
4874  if( minavailable < maxavailable && est < minbegin )
4875  {
4876  assert(!(*cutoff));
4877 
4878  /* try to tighten the upper bound */
4879  SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4880  var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4881  initialized, explanation, cutoff) );
4882 
4883  if( *cutoff )
4884  break;
4885  }
4886 
4887  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4888  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4889 
4890  begin = est;
4891  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4892 
4893  /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4894  * free energy
4895  */
4896  if( begin < hmin )
4897  break;
4898 
4899  /* compute the contribution to the flexible energy */
4900  if( lct <= end )
4901  {
4902  /* if the jobs has to finish before the end, all the energy has to be scheduled */
4903  assert(lst >= begin);
4904  assert(flexenergies[idx] >= 0);
4905  flexenergy += flexenergies[idx];
4906  }
4907  else
4908  {
4909  /* the job partly overlaps with the end */
4910  int candenergy;
4911  int energy;
4912 
4913  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4914  * w.r.t. latest start time
4915  *
4916  * @note we need to be aware of the effective horizon
4917  */
4918  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4919  assert(end - lst < duration);
4920  assert(energy >= 0);
4921 
4922  /* adjust the flexible energy of the time interval */
4923  flexenergy += energy;
4924 
4925  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4926  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4927  assert(candenergy >= 0);
4928 
4929  /* check if we found a better candidate */
4930  if( candenergy > lbenergy )
4931  {
4932  lbenergy = candenergy;
4933  lbcand = idx;
4934  }
4935  }
4936 
4937  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4938  assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4939 
4940  /* compute the energy which is not used yet */
4941  freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4942 
4943  /* check overload */
4944  if( freeenergy < 0 )
4945  {
4946  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4947 
4948  /* initialize conflict analysis if conflict analysis is applicable */
4950  {
4951  /* analyze infeasibilty */
4953 
4954  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4955  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
4956  conshdlrdata->usebdwidening, explanation) );
4957 
4958  (*initialized) = TRUE;
4959  }
4960 
4961  (*cutoff) = TRUE;
4962 
4963  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4964  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
4965 
4966  break;
4967  }
4968 
4969  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4970  if( lbenergy > 0 && freeenergy < lbenergy )
4971  {
4972  SCIP_Longint energy;
4973  int newlb;
4974  int ect;
4975 
4976  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4977  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4978 
4979  /* remove the energy of our job from the ... */
4980  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) end - lsts[lbcand])) * demands[lbcand];
4981 
4982  newlb = end - (int)(energy / demands[lbcand]);
4983 
4984  if( newlb > lst )
4985  {
4986  /* initialize conflict analysis if conflict analysis is applicable */
4988  {
4989  SCIP_Real relaxedbd;
4990 
4991  /* analyze infeasibilty */
4993 
4994  relaxedbd = lst + 1.0;
4995 
4996  /* added to upper bound (which was overcut be new lower bound) of the variable */
4997  SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4998 
4999  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5000  begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
5001  conshdlrdata->usebdwidening, explanation) );
5002 
5003  (*initialized) = TRUE;
5004  }
5005 
5006  (*cutoff) = TRUE;
5007  break;
5008  }
5009  else if( newlb > newlbs[lbcand] )
5010  {
5011  INFERINFO inferinfo;
5012 
5013  /* construct inference information */
5014  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5015 
5016  /* buffer upper bound change */
5017  lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
5018  newlbs[lbcand] = newlb;
5019  }
5020  }
5021 
5022  /* check if the current interval has a smaller free energy */
5023  if( minavailable > freeenergy )
5024  {
5025  minavailable = freeenergy;
5026  minbegin = begin;
5027  }
5028  assert(minavailable >= 0);
5029  }
5030  }
5031 
5032  return SCIP_OKAY;
5033 }
5034 
5035 /** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
5036 static
5038  SCIP* scip, /**< SCIP data structure */
5039  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5040  int nvars, /**< number of start time variables (activities) */
5041  SCIP_VAR** vars, /**< array of start time variables */
5042  int* durations, /**< array of durations */
5043  int* demands, /**< array of demands */
5044  int capacity, /**< cumulative capacity */
5045  int hmin, /**< left bound of time axis to be considered (including hmin) */
5046  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5047  int* newlbs, /**< array to buffer new lower bounds */
5048  int* newubs, /**< array to buffer new upper bounds */
5049  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
5050  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
5051  int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
5052  int* flexenergies, /**< array of flexible energies in the same order as the variables */
5053  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
5054  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
5055  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
5056  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
5057  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
5058  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5059  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5060  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5061  )
5062 {
5063  int coreEnergyAfterStart;
5064  SCIP_Longint maxavailable;
5065  SCIP_Longint minavailable;
5066  SCIP_Longint totalenergy;
5067  int nlcts;
5068  int begin;
5069  int minest;
5070  int maxlct;
5071  int start;
5072  int end;
5073  int v;
5074 
5075  if( *cutoff )
5076  return SCIP_OKAY;
5077 
5078  begin = hmin - 1;
5079 
5080  minest = INT_MAX;
5081  maxlct = INT_MIN;
5082 
5083  /* compute earliest start and latest completion time of all jobs */
5084  for( v = 0; v < nvars; ++v )
5085  {
5086  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5087  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
5088 
5089  minest = MIN(minest, start);
5090  maxlct = MAX(maxlct, end);
5091  }
5092 
5093  /* adjust the effective time horizon */
5094  hmin = MAX(hmin, minest);
5095  hmax = MIN(hmax, maxlct);
5096 
5097  maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
5098  totalenergy = computeTotalEnergy(durations, demands, nvars);
5099 
5100  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5101  if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5102  return SCIP_OKAY;
5103 
5104  nlcts = 0;
5105 
5106  /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5107  * define the start of the time interval under investigation
5108  */
5109  for( v = 0; v < nvars; ++v )
5110  {
5111  int flexenergy;
5112  int minend;
5113  int ubenergy;
5114  int ubcand;
5115  int est;
5116  int i;
5117 
5118  est = ests[v];
5119 
5120  /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5121  * infinity capacity is available; hence we skip that
5122  */
5123  if( est < hmin )
5124  continue;
5125 
5126  /* if the earliest start time is larger or equal then hmax we have to stop */
5127  if( est >= hmax )
5128  break;
5129 
5130  /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5131  * induced by start was just analyzed
5132  */
5133  if( est == begin )
5134  continue;
5135 
5136  assert(est > begin);
5137 
5138  SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5139 
5140  begin = est;
5141  coreEnergyAfterStart = coreEnergyAfterEst[v];
5142 
5143  flexenergy = 0;
5144  minavailable = maxavailable;
5145  minend = hmin;
5146  ubcand = -1;
5147  ubenergy = 0;
5148 
5149  /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5150  * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5151  */
5152  for( i = nlcts; i < nvars; ++i )
5153  {
5154  SCIP_VAR* var;
5155  SCIP_Longint freeenergy;
5156  int duration;
5157  int demand;
5158  int idx;
5159  int lct;
5160  int ect;
5161 
5162  idx = perm[i];
5163  assert(idx >= 0);
5164  assert(idx < nvars);
5165  assert(!(*cutoff));
5166 
5167  /* the earliest start time of the job */
5168  lct = lcts[i];
5169 
5170  /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5171  * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5172  */
5173  if( lct <= begin )
5174  {
5175  nlcts++;
5176  continue;
5177  }
5178 
5179  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5180  * start with current beginning time
5181  */
5182  if( ((SCIP_Longint) lct - begin) * capacity >= totalenergy )
5183  break;
5184 
5185  var = vars[idx];
5186  assert(var != NULL);
5187 
5188  duration = durations[idx];
5189  assert(duration > 0);
5190 
5191  demand = demands[idx];
5192  assert(demand > 0);
5193 
5194  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5195 
5196  /* the earliest completion time of the flexible part of the job */
5197  ect = ects[idx];
5198 
5199  /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5200  * investigation; hence the overload check will do the the job
5201  */
5202  assert(lct >= minend);
5203  if( minavailable < maxavailable && lct > minend )
5204  {
5205  assert(!(*cutoff));
5206 
5207  /* try to tighten the upper bound */
5208  SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5209  var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5210  initialized, explanation, cutoff) );
5211 
5212  if( *cutoff )
5213  return SCIP_OKAY;
5214  }
5215 
5216  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5217  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5218 
5219  end = lct;
5220  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5221 
5222  /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5223  * free energy
5224  */
5225  if( end > hmax )
5226  break;
5227 
5228  /* compute the contribution to the flexible energy */
5229  if( est >= begin )
5230  {
5231  /* if the jobs has to finish before the end, all the energy has to be scheduled */
5232  assert(ect <= end);
5233  assert(flexenergies[idx] >= 0);
5234  flexenergy += flexenergies[idx];
5235  }
5236  else
5237  {
5238  /* the job partly overlaps with the end */
5239  int candenergy;
5240  int energy;
5241 
5242  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5243  * w.r.t. latest start time
5244  *
5245  * @note we need to be aware of the effective horizon
5246  */
5247  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5248  assert(ect - begin < duration);
5249  assert(energy >= 0);
5250 
5251  /* adjust the flexible energy of the time interval */
5252  flexenergy += energy;
5253 
5254  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5255  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5256  assert(candenergy >= 0);
5257 
5258  /* check if we found a better candidate */
5259  if( candenergy > ubenergy )
5260  {
5261  ubenergy = candenergy;
5262  ubcand = idx;
5263  }
5264  }
5265 
5266  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5267  assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5268 
5269  /* compute the energy which is not used yet */
5270  freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5271 
5272  /* check overload */
5273  if( freeenergy < 0 )
5274  {
5275  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5276 
5277  /* initialize conflict analysis if conflict analysis is applicable */
5279  {
5280  /* analyze infeasibilty */
5282 
5283  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5284  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
5285  conshdlrdata->usebdwidening, explanation) );
5286 
5287  (*initialized) = TRUE;
5288  }
5289 
5290  (*cutoff) = TRUE;
5291 
5292  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5293  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5294 
5295  return SCIP_OKAY;
5296  }
5297 
5298  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5299  if( ubenergy > 0 && freeenergy < ubenergy )
5300  {
5301  SCIP_Longint energy;
5302  int newub;
5303  int lst;
5304 
5305  duration = durations[ubcand];
5306  assert(duration > 0);
5307 
5308  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5309  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5310 
5311  /* remove the energy of our job from the ... */
5312  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) ects[ubcand] - begin)) * demands[ubcand];
5313 
5314  newub = begin - duration + (int)(energy / demands[ubcand]);
5315 
5316  if( newub < ect - duration )
5317  {
5318  /* initialize conflict analysis if conflict analysis is applicable */
5320  {
5321  SCIP_Real relaxedbd;
5322  /* analyze infeasibilty */
5324 
5325  relaxedbd = ect - duration - 1.0;
5326 
5327  /* added to lower bound (which was undercut be new upper bound) of the variable */
5328  SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5329 
5330  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5331  begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5332  conshdlrdata->usebdwidening, explanation) );
5333 
5334  (*initialized) = TRUE;
5335  }
5336 
5337  (*cutoff) = TRUE;
5338  return SCIP_OKAY;
5339  }
5340  else if( newub < newubs[ubcand] )
5341  {
5342  INFERINFO inferinfo;
5343 
5344  /* construct inference information */
5345  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5346 
5347  /* buffer upper bound change */
5348  ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5349  newubs[ubcand] = newub;
5350  }
5351  }
5352 
5353  /* check if the current interval has a smaller free energy */
5354  if( minavailable > freeenergy )
5355  {
5356  minavailable = freeenergy;
5357  minend = end;
5358  }
5359  assert(minavailable >= 0);
5360  }
5361  }
5362 
5363  return SCIP_OKAY;
5364 }
5365 
5366 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5367  * edge-finding
5368  *
5369  * @note The algorithm is based on the following two papers:
5370  * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5371  * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5372  * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5373  * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5374  * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5375  */
5376 static
5378  SCIP* scip, /**< SCIP data structure */
5379  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5380  SCIP_PROFILE* profile, /**< current core profile */
5381  int nvars, /**< number of start time variables (activities) */
5382  SCIP_VAR** vars, /**< array of start time variables */
5383  int* durations, /**< array of durations */
5384  int* demands, /**< array of demands */
5385  int capacity, /**< cumulative capacity */
5386  int hmin, /**< left bound of time axis to be considered (including hmin) */
5387  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5388  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5389  int* nchgbds, /**< pointer to store the number of bound changes */
5390  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5391  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5392  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5393  )
5394 {
5395  int* coreEnergyAfterEst;
5396  int* coreEnergyAfterLct;
5397  int* flexenergies;
5398  int* permests;
5399  int* permlcts;
5400  int* lcts;
5401  int* ests;
5402  int* ects;
5403  int* lsts;
5404 
5405  int* newlbs;
5406  int* newubs;
5407  int* lbinferinfos;
5408  int* ubinferinfos;
5409 
5410  int v;
5411 
5412  /* check if a cutoff was already detected */
5413  if( (*cutoff) )
5414  return SCIP_OKAY;
5415 
5416  /* check if at least the basic overload checking should be perfomed */
5417  if( !conshdlrdata->ttefcheck )
5418  return SCIP_OKAY;
5419 
5420  SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5421 
5422  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5423  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5424  SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5425  SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5426  SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5427  SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5428  SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5429  SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5430  SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5431 
5432  SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5433  SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5434  SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5435  SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5436 
5437  /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5438  for( v = 0; v < nvars; ++v )
5439  {
5440  newlbs[v] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5441  newubs[v] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5442  lbinferinfos[v] = 0;
5443  ubinferinfos[v] = 0;
5444  }
5445 
5446  /* collect earliest start times, latest completion time, and free energy contributions */
5447  collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5448 
5449  /* sort the earliest start times and latest completion in non-decreasing order */
5450  SCIPsortIntInt(ests, permests, nvars);
5451  SCIPsortIntInt(lcts, permlcts, nvars);
5452 
5453  /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5454  * points
5455  */
5456  computeCoreEnergyAfter(profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct);
5457 
5458  /* propagate the upper bounds and "opportunistically" the lower bounds */
5459  SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5460  newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5461  permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5462 
5463  /* propagate the lower bounds and "opportunistically" the upper bounds */
5464  SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5465  newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5466  permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5467 
5468  /* apply the buffer bound changes */
5469  for( v = 0; v < nvars && !(*cutoff); ++v )
5470  {
5471  SCIP_Bool infeasible;
5472  SCIP_Bool tightened;
5473 
5474  if( inferInfoIsValid(intToInferInfo(lbinferinfos[v])) )
5475  {
5476  SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v],
5477  TRUE, &infeasible, &tightened) );
5478  }
5479  else
5480  {
5481  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], (SCIP_Real)newlbs[v], TRUE, &infeasible, &tightened) );
5482  }
5483 
5484  /* since we change first the lower bound of the variable an infeasibilty should not be detected */
5485  assert(!infeasible);
5486 
5487  if( tightened )
5488  {
5489  (*nchgbds)++;
5490 
5491  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5493  }
5494 
5495  if( inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
5496  {
5497  SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v],
5498  TRUE, &infeasible, &tightened) );
5499  }
5500  else
5501  {
5502  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], (SCIP_Real)newubs[v], TRUE, &infeasible, &tightened) );
5503  }
5504 
5505  /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5506  * bound update can be infeasible
5507  */
5508  if( infeasible )
5509  {
5510  /* a small performance improvement is possible here: if the tighten...TEFF and propagate...TEFF methods would
5511  * return not only the inferinfos, but the actual begin and end values, then the infeasibility here could also
5512  * be analyzed in the case when begin and end exceed the 15 bit limit
5513  */
5514  if( SCIPisConflictAnalysisApplicable(scip) && inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
5515  {
5516  INFERINFO inferinfo;
5517  SCIP_VAR* var;
5518  int begin;
5519  int end;
5520 
5521  var = vars[v];
5522  assert(var != NULL);
5523 
5524  /* initialize conflict analysis */
5526 
5527  /* convert int to inference information */
5528  inferinfo = intToInferInfo(ubinferinfos[v]);
5529 
5530  /* collect time window from inference information */
5531  begin = inferInfoGetData1(inferinfo);
5532  end = inferInfoGetData2(inferinfo);
5533  assert(begin < end);
5534 
5535  /* added to lower bound (which was undercut be new upper bound) of the variable */
5536  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
5537 
5538  /* analysis the upper bound change */
5539  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5540  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5541  conshdlrdata->usebdwidening, explanation) );
5542 
5543  (*initialized) = TRUE;
5544  }
5545 
5546  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5547  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5548 
5549  (*cutoff) = TRUE;
5550  break;
5551  }
5552 
5553  if( tightened )
5554  {
5555  (*nchgbds)++;
5556 
5557  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5559  }
5560  }
5561 
5562  SCIPfreeBufferArray(scip, &ubinferinfos);
5563  SCIPfreeBufferArray(scip, &lbinferinfos);
5564  SCIPfreeBufferArray(scip, &newubs);
5565  SCIPfreeBufferArray(scip, &newlbs);
5566 
5567  /* free buffer arrays */
5568  SCIPfreeBufferArray(scip, &lsts);
5569  SCIPfreeBufferArray(scip, &ects);
5570  SCIPfreeBufferArray(scip, &ests);
5571  SCIPfreeBufferArray(scip, &lcts);
5572  SCIPfreeBufferArray(scip, &permests);
5573  SCIPfreeBufferArray(scip, &permlcts);
5574  SCIPfreeBufferArray(scip, &flexenergies);
5575  SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5576  SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5577 
5578  return SCIP_OKAY;
5579 }
5580 
5581 /** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5582  * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5583  * time table propagator
5584  */
5585 static
5587  SCIP* scip, /**< SCIP data structure */
5588  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5589  SCIP_PROFILE* profile, /**< core profile */
5590  int nvars, /**< number of start time variables (activities) */
5591  SCIP_VAR** vars, /**< array of start time variables */
5592  int* durations, /**< array of durations */
5593  int* demands, /**< array of demands */
5594  int capacity, /**< cumulative capacity */
5595  int hmin, /**< left bound of time axis to be considered (including hmin) */
5596  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5597  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5598  int* nchgbds, /**< pointer to store the number of bound changes */
5599  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5600  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5601  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5602  )
5603 {
5604  SCIP_Bool infeasible;
5605  int v;
5606 
5607  assert(scip != NULL);
5608  assert(nvars > 0);
5609  assert(cons != NULL);
5610  assert(cutoff != NULL);
5611 
5612  /* check if already a cutoff was detected */
5613  if( (*cutoff) )
5614  return SCIP_OKAY;
5615 
5616  /* check if the time tabling should infer bounds */
5617  if( !conshdlrdata->ttinfer )
5618  return SCIP_OKAY;
5619 
5620  assert(*initialized == FALSE);
5621 
5622  SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5623  SCIPconsGetName(cons), hmin, hmax, capacity);
5624 
5625  infeasible = FALSE;
5626 
5627  /* if core profile is empty; nothing to do */
5628  if( SCIPprofileGetNTimepoints(profile) <= 1 )
5629  return SCIP_OKAY;
5630 
5631  /* start checking each job whether the bounds can be improved */
5632  for( v = 0; v < nvars; ++v )
5633  {
5634  SCIP_VAR* var;
5635  int demand;
5636  int duration;
5637  int begin;
5638  int end;
5639  int est;
5640  int lst;
5641 
5642  var = vars[v];
5643  assert(var != NULL);
5644 
5645  duration = durations[v];
5646  assert(duration > 0);
5647 
5648  /* collect earliest and latest start time */
5649  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5650  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5651 
5652  /* check if the start time variables is already fixed; in that case we can ignore the job */
5653  if( est == lst )
5654  continue;
5655 
5656  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5657  if( lst + duration <= hmin || est >= hmax )
5658  continue;
5659 
5660  /* compute core interval w.r.t. effective time horizon */
5661  begin = MAX(hmin, lst);
5662  end = MIN(hmax, est + duration);
5663 
5664  demand = demands[v];
5665  assert(demand > 0);
5666 
5667  /* if the job has a core, remove it first */
5668  if( begin < end )
5669  {
5670  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5671  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5672 
5673  SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5674  }
5675 
5676  /* first try to update the earliest start time */
5677  SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5678  profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5679 
5680  if( *cutoff )
5681  break;
5682 
5683  /* second try to update the latest start time */
5684  SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5685  profile, v, nchgbds) );
5686 
5687  if( *cutoff )
5688  break;
5689 
5690  /* collect the potentially updated earliest and latest start time */
5691  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5692  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5693 
5694  /* compute core interval w.r.t. effective time horizon */
5695  begin = MAX(hmin, lst);
5696  end = MIN(hmax, est + duration);
5697 
5698  /* after updating the bound we might have a new core */
5699  if( begin < end )
5700  {
5701  int pos;
5702 
5703  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5704  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5705 
5706  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5707 
5708  if( infeasible )
5709  {
5710  /* use conflict analysis to analysis the core insertion which was infeasible */
5711  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5712  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5713 
5714  if( explanation != NULL )
5715  explanation[v] = TRUE;
5716 
5717  (*cutoff) = TRUE;
5718 
5719  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5720  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
5721 
5722  break;
5723  }
5724  }
5725  }
5726 
5727  return SCIP_OKAY;
5728 }
5729 
5730 
5731 /** node data structure for the binary tree used for edgefinding (with overload checking) */
5732 struct SCIP_NodeData
5733 {
5734  SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5735  SCIP_Real key; /**< key which is to insert the corresponding search node */
5736  int est; /**< earliest start time if the node data belongs to a leaf */
5737  int lct; /**< latest completion time if the node data belongs to a leaf */
5738  int demand; /**< demand of the job if the node data belongs to a leaf */
5739  int duration; /**< duration of the job if the node data belongs to a leaf */
5740  int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5741  int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5742  SCIP_Longint enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5743  int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5744  int energylambda;
5745  SCIP_Longint enveloplambda;
5746  int idx; /**< index of the start time variable in the (global) variable array */
5747  SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5748 };
5749 typedef struct SCIP_NodeData SCIP_NODEDATA;
5751 
5752 /** update node data structure starting from the given node along the path to the root node */
5753 static
5754 void updateEnvelope(
5755  SCIP* scip, /**< SCIP data structure */
5756  SCIP_BTNODE* node /**< search node which inserted */
5757  )
5758 {
5759  SCIP_BTNODE* left;
5760  SCIP_BTNODE* right;
5761  SCIP_NODEDATA* nodedata;
5762  SCIP_NODEDATA* leftdata;
5763  SCIP_NODEDATA* rightdata;
5764 
5765  SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5766 
5767  if( SCIPbtnodeIsLeaf(node) )
5768  node = SCIPbtnodeGetParent(node);
5769 
5770  while( node != NULL )
5771  {
5772  /* get node data */
5773  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5774  assert(nodedata != NULL);
5775 
5776  /* collect node data from left node */
5777  left = SCIPbtnodeGetLeftchild(node);
5778  assert(left != NULL);
5779  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5780  assert(leftdata != NULL);
5781 
5782  /* collect node data from right node */
5783  right = SCIPbtnodeGetRightchild(node);
5784  assert(right != NULL);
5785  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5786  assert(rightdata != NULL);
5787 
5788  /* update envelop and energy */
5789  if( leftdata->enveloptheta >= 0 )
5790  {
5791  assert(rightdata->energytheta != -1);
5792  nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5793  }
5794  else
5795  nodedata->enveloptheta = rightdata->enveloptheta;
5796 
5797  assert(leftdata->energytheta != -1);
5798  assert(rightdata->energytheta != -1);
5799  nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5800 
5801  if( leftdata->enveloplambda >= 0 )
5802  {
5803  assert(rightdata->energytheta != -1);
5804  nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5805  }
5806  else
5807  nodedata->enveloplambda = rightdata->enveloplambda;
5808 
5809  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5810  nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5811 
5812  SCIPdebugMsg(scip, "node <%p> lambda envelop %" SCIP_LONGINT_FORMAT "\n", (void*)node, nodedata->enveloplambda);
5813 
5814  if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5815  {
5816  assert(rightdata->energytheta != -1);
5817  assert(leftdata->energytheta != -1);
5818  nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5819  }
5820  else if( rightdata->energylambda >= 0 )
5821  {
5822  assert(leftdata->energytheta != -1);
5823  nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5824  }
5825  else if( leftdata->energylambda >= 0 )
5826  {
5827  assert(rightdata->energytheta != -1);
5828  nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5829  }
5830  else
5831  nodedata->energylambda = -1;
5832 
5833  /* go to parent */
5834  node = SCIPbtnodeGetParent(node);
5835  }
5836 
5837  SCIPdebugMsg(scip, "updating done\n");
5838 }
5839 
5840 /** updates the key of the first parent on the trace which comes from left */
5841 static
5842 void updateKeyOnTrace(
5843  SCIP_BTNODE* node, /**< node to start the trace */
5844  SCIP_Real key /**< update search key */
5845  )
5846 {
5847  assert(node != NULL);
5848 
5849  while( !SCIPbtnodeIsRoot(node) )
5850  {
5851  SCIP_BTNODE* parent;
5852 
5853  parent = SCIPbtnodeGetParent(node);
5854  assert(parent != NULL);
5855 
5856  if( SCIPbtnodeIsLeftchild(node) )
5857  {
5858  SCIP_NODEDATA* nodedata;
5859 
5860  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(parent);
5861  assert(nodedata != NULL);
5862 
5863  nodedata->key = key;
5864  return;
5865  }
5866 
5867  node = parent;
5868  }
5869 }
5870 
5871 
5872 /** deletes the given node and updates all envelops */
5873 static
5875  SCIP* scip, /**< SCIP data structure */
5876  SCIP_BT* tree, /**< binary tree */
5877  SCIP_BTNODE* node /**< node to be deleted */
5878  )
5879 {
5880  SCIP_BTNODE* parent;
5881  SCIP_BTNODE* grandparent;
5882  SCIP_BTNODE* sibling;
5883 
5884  assert(scip != NULL);
5885  assert(tree != NULL);
5886  assert(node != NULL);
5887 
5888  assert(SCIPbtnodeIsLeaf(node));
5889  assert(!SCIPbtnodeIsRoot(node));
5890 
5891  SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5892 
5893  parent = SCIPbtnodeGetParent(node);
5894  assert(parent != NULL);
5895  if( SCIPbtnodeIsLeftchild(node) )
5896  {
5897  sibling = SCIPbtnodeGetRightchild(parent);
5898  SCIPbtnodeSetRightchild(parent, NULL);
5899  }
5900  else
5901  {
5902  sibling = SCIPbtnodeGetLeftchild(parent);
5903  SCIPbtnodeSetLeftchild(parent, NULL);
5904  }
5905  assert(sibling != NULL);
5906 
5907  grandparent = SCIPbtnodeGetParent(parent);
5908 
5909  if( grandparent != NULL )
5910  {
5911  /* reset parent of sibling */
5912  SCIPbtnodeSetParent(sibling, grandparent);
5913 
5914  /* reset child of grandparent to sibling */
5915  if( SCIPbtnodeIsLeftchild(parent) )
5916  {
5917  SCIPbtnodeSetLeftchild(grandparent, sibling);
5918  }
5919  else
5920  {
5921  SCIP_NODEDATA* nodedata;
5922 
5923  assert(SCIPbtnodeIsRightchild(parent));
5924  SCIPbtnodeSetRightchild(grandparent, sibling);
5925 
5926  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(sibling);
5927 
5928  updateKeyOnTrace(grandparent, nodedata->key);
5929  }
5930 
5931  updateEnvelope(scip, grandparent);
5932  }
5933  else
5934  {
5935  SCIPbtnodeSetParent(sibling, NULL);
5936 
5937  SCIPbtSetRoot(tree, sibling);
5938  }
5939 
5940  SCIPbtnodeFree(tree, &parent);
5941 
5942  return SCIP_OKAY;
5943 }
5944 
5945 /** moves a node form the theta set into the lambda set and updates the envelops */
5946 static
5948  SCIP* scip, /**< SCIP data structure */
5949  SCIP_BT* tree, /**< binary tree */
5950  SCIP_BTNODE* node /**< node to move into the lambda set */
5951  )
5952 {
5953  SCIP_NODEDATA* nodedata;
5954 
5955  assert(scip != NULL);
5956  assert(tree != NULL);
5957  assert(node != NULL);
5958 
5959  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5960  assert(nodedata != NULL);
5961  assert(nodedata->intheta);
5962 
5963  /* move the contributions form the theta set into the lambda set */
5964  assert(nodedata->enveloptheta != -1);
5965  assert(nodedata->energytheta != -1);
5966  assert(nodedata->enveloplambda == -1);
5967  assert(nodedata->energylambda == -1);
5968  nodedata->enveloplambda = nodedata->enveloptheta;
5969  nodedata->energylambda = nodedata->energytheta;
5970 
5971  nodedata->enveloptheta = -1;
5972  nodedata->energytheta = 0;
5973  nodedata->intheta = FALSE;
5974 
5975  /* update the energy and envelop values on trace */
5976  updateEnvelope(scip, node);
5977 
5978  return SCIP_OKAY;
5979 }
5980 
5981 /** inserts a node into the theta set and update the envelops */
5982 static
5984  SCIP* scip, /**< SCIP data structure */
5985  SCIP_BT* tree, /**< binary tree */
5986  SCIP_BTNODE* node, /**< node to insert */
5987  SCIP_NODEDATA* nodedatas, /**< array of node data */
5988  int* nodedataidx, /**< array of indices for node data */
5989  int* nnodedatas /**< pointer to number of node data */
5990  )
5991 {
5992  /* if the tree is empty the node will be the root node */
5993  if( SCIPbtIsEmpty(tree) )
5994  {
5995  SCIPbtSetRoot(tree, node);
5996  }
5997  else
5998  {
5999  SCIP_NODEDATA* newnodedata;
6000  SCIP_NODEDATA* leafdata;
6001  SCIP_NODEDATA* nodedata;
6002  SCIP_BTNODE* leaf;
6003  SCIP_BTNODE* newnode;
6004  SCIP_BTNODE* parent;
6005 
6006  leaf = SCIPbtGetRoot(tree);
6007  assert(leaf != NULL);
6008 
6009  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6010  assert(leafdata != NULL);
6011 
6012  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6013  assert(nodedata != NULL);
6014  assert(nodedata->intheta);
6015 
6016  /* find the position to insert the node */
6017  while( !SCIPbtnodeIsLeaf(leaf) )
6018  {
6019  if( nodedata->key < leafdata->key )
6020  leaf = SCIPbtnodeGetLeftchild(leaf);
6021  else
6022  leaf = SCIPbtnodeGetRightchild(leaf);
6023 
6024  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6025  assert(leafdata != NULL);
6026  }
6027 
6028  assert(leaf != NULL);
6029  assert(leaf != node);
6030 
6031  /* store node data to be able to delete them latter */
6032  newnodedata = &nodedatas[*nnodedatas];
6033  nodedataidx[*nnodedatas] = *nnodedatas;
6034  ++(*nnodedatas);
6035 
6036  /* init node data */
6037  newnodedata->var = NULL;
6038  newnodedata->key = SCIP_INVALID;
6039  newnodedata->est = INT_MIN;
6040  newnodedata->lct = INT_MAX;
6041  newnodedata->duration = 0;
6042  newnodedata->demand = 0;
6043  newnodedata->enveloptheta = -1;
6044  newnodedata->energytheta = 0;
6045  newnodedata->enveloplambda = -1;
6046  newnodedata->energylambda = -1;
6047  newnodedata->idx = -1;
6048  newnodedata->intheta = TRUE;
6049 
6050  /* create a new node */
6051  SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
6052  assert(newnode != NULL);
6053 
6054  parent = SCIPbtnodeGetParent(leaf);
6055 
6056  if( parent != NULL )
6057  {
6058  SCIPbtnodeSetParent(newnode, parent);
6059 
6060  /* check if the node is the left child */
6061  if( SCIPbtnodeGetLeftchild(parent) == leaf )
6062  {
6063  SCIPbtnodeSetLeftchild(parent, newnode);
6064  }
6065  else
6066  {
6067  SCIPbtnodeSetRightchild(parent, newnode);
6068  }
6069  }
6070  else
6071  SCIPbtSetRoot(tree, newnode);
6072 
6073  if( nodedata->key < leafdata->key )
6074  {
6075  /* node is on the left */
6076  SCIPbtnodeSetLeftchild(newnode, node);
6077  SCIPbtnodeSetRightchild(newnode, leaf);
6078  newnodedata->key = nodedata->key;
6079  }
6080  else
6081  {
6082  /* leaf is on the left */
6083  SCIPbtnodeSetLeftchild(newnode, leaf);
6084  SCIPbtnodeSetRightchild(newnode, node);
6085  newnodedata->key = leafdata->key;
6086  }
6087 
6088  SCIPbtnodeSetParent(leaf, newnode);
6089  SCIPbtnodeSetParent(node, newnode);
6090  }
6091 
6092  /* update envelop */
6093  updateEnvelope(scip, node);
6094 
6095  return SCIP_OKAY;
6096 }
6097 
6098 /** returns the leaf responsible for the lambda energy */
6099 static
6101  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6102  )
6103 {
6104  SCIP_BTNODE* left;
6105  SCIP_BTNODE* right;
6106  SCIP_NODEDATA* nodedata;
6107  SCIP_NODEDATA* leftdata;
6108  SCIP_NODEDATA* rightdata;
6109 
6110  assert(node != NULL);
6111 
6112  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6113  assert(nodedata != NULL);
6114 
6115  /* check if the node is the (responsible) leaf */
6116  if( SCIPbtnodeIsLeaf(node) )
6117  {
6118  assert(!nodedata->intheta);
6119  return node;
6120  }
6121 
6122  left = SCIPbtnodeGetLeftchild(node);
6123  assert(left != NULL);
6124 
6125  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6126  assert(leftdata != NULL);
6127 
6128  right = SCIPbtnodeGetRightchild(node);
6129  assert(right != NULL);
6130 
6131  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6132  assert(rightdata != NULL);
6133 
6134  assert(nodedata->energylambda != -1);
6135  assert(rightdata->energytheta != -1);
6136 
6137  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6139 
6140  assert(leftdata->energytheta != -1);
6141  assert(rightdata->energylambda != -1);
6142  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6143 
6145 }
6146 
6147 /** returns the leaf responsible for the lambda envelop */
6148 static
6150  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6151  )
6152 {
6153  SCIP_BTNODE* left;
6154  SCIP_BTNODE* right;
6155  SCIP_NODEDATA* nodedata;
6156  SCIP_NODEDATA* leftdata;
6157  SCIP_NODEDATA* rightdata;
6158 
6159  assert(node != NULL);
6160 
6161  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6162  assert(nodedata != NULL);
6163 
6164  /* check if the node is the (responsible) leaf */
6165  if( SCIPbtnodeIsLeaf(node) )
6166  {
6167  assert(!nodedata->intheta);
6168  return node;
6169  }
6170 
6171  left = SCIPbtnodeGetLeftchild(node);
6172  assert(left != NULL);
6173 
6174  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6175  assert(leftdata != NULL);
6176 
6177  right = SCIPbtnodeGetRightchild(node);
6178  assert(right != NULL);
6179 
6180  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6181  assert(rightdata != NULL);
6182 
6183  assert(nodedata->enveloplambda != -1);
6184  assert(rightdata->energytheta != -1);
6185 
6186  /* check if the left or right child is the one defining the envelop for the lambda set */
6187  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6189  else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6190  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6192 
6193  assert(rightdata->enveloplambda != -1);
6194  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6195 
6197 }
6198 
6199 
6200 /** reports all elements from set theta to generate a conflicting set */
6201 static
6202 void collectThetaSubtree(
6203  SCIP_BTNODE* node, /**< node within a theta subtree */
6204  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6205  int* nelements, /**< pointer to store the number of elements in omegaset */
6206  int* est, /**< pointer to store the earliest start time of the omega set */
6207  int* lct, /**< pointer to store the latest start time of the omega set */
6208  int* energy /**< pointer to store the energy of the omega set */
6209  )
6210 {
6211  SCIP_NODEDATA* nodedata;
6212 
6213  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6214  assert(nodedata != NULL);
6215 
6216  if( !SCIPbtnodeIsLeaf(node) )
6217  {
6218  collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6219  collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6220  }
6221  else if( nodedata->intheta )
6222  {
6223  assert(nodedata->var != NULL);
6224  SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6225 
6226  omegaset[*nelements] = node;
6227  (*est) = MIN(*est, nodedata->est);
6228  (*lct) = MAX(*lct, nodedata->lct);
6229  (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6230  (*nelements)++;
6231  }
6232 }
6233 
6234 
6235 /** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6236 static
6237 void traceThetaEnvelop(
6238  SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6239  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6240  int* nelements, /**< pointer to store the number of elements in omegaset */
6241  int* est, /**< pointer to store the earliest start time of the omega set */
6242  int* lct, /**< pointer to store the latest start time of the omega set */
6243  int* energy /**< pointer to store the energy of the omega set */
6244  )
6245 {
6246  assert(node != NULL);
6247 
6248  if( SCIPbtnodeIsLeaf(node) )
6249  {
6250  collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6251  }
6252  else
6253  {
6254  SCIP_BTNODE* left;
6255  SCIP_BTNODE* right;
6256  SCIP_NODEDATA* nodedata;
6257  SCIP_NODEDATA* leftdata;
6258  SCIP_NODEDATA* rightdata;
6259 
6260  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6261  assert(nodedata != NULL);
6262 
6263  left = SCIPbtnodeGetLeftchild(node);
6264  assert(left != NULL);
6265 
6266  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6267  assert(leftdata != NULL);
6268 
6269  right = SCIPbtnodeGetRightchild(node);
6270  assert(right != NULL);
6271 
6272  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6273  assert(rightdata != NULL);
6274 
6275  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6276  assert(nodedata != NULL);
6277 
6278  assert(nodedata->enveloptheta != -1);
6279  assert(rightdata->energytheta != -1);
6280 
6281  if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6282  {
6283  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6284  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6285  }
6286  else
6287  {
6288  assert(rightdata->enveloptheta != -1);
6289  assert(nodedata->enveloptheta == rightdata->enveloptheta);
6290  traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6291  }
6292  }
6293 }
6294 
6295 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6296 static
6297 void traceLambdaEnergy(
6298  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6299  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6300  int* nelements, /**< pointer to store the number of elements in omega set */
6301  int* est, /**< pointer to store the earliest start time of the omega set */
6302  int* lct, /**< pointer to store the latest start time of the omega set */
6303  int* energy /**< pointer to store the energy of the omega set */
6304  )
6305 {
6306  SCIP_BTNODE* left;
6307  SCIP_BTNODE* right;
6308  SCIP_NODEDATA* nodedata;
6309  SCIP_NODEDATA* leftdata;
6310  SCIP_NODEDATA* rightdata;
6311 
6312  assert(node != NULL);
6313 
6314  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6315  assert(nodedata != NULL);
6316 
6317  /* check if the node is a leaf */
6318  if( SCIPbtnodeIsLeaf(node) )
6319  return;
6320 
6321  left = SCIPbtnodeGetLeftchild(node);
6322  assert(left != NULL);
6323 
6324  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6325  assert(leftdata != NULL);
6326 
6327  right = SCIPbtnodeGetRightchild(node);
6328  assert(right != NULL);
6329 
6330  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6331  assert(rightdata != NULL);
6332 
6333  assert(nodedata->energylambda != -1);
6334  assert(rightdata->energytheta != -1);
6335 
6336  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6337  {
6338  traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6339  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6340  }
6341  else
6342  {
6343  assert(leftdata->energytheta != -1);
6344  assert(rightdata->energylambda != -1);
6345  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6346 
6347  collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6348  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6349  }
6350 }
6351 
6352 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6353 static
6354 void traceLambdaEnvelop(
6355  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6356  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6357  int* nelements, /**< pointer to store the number of elements in omega set */
6358  int* est, /**< pointer to store the earliest start time of the omega set */
6359  int* lct, /**< pointer to store the latest start time of the omega set */
6360  int* energy /**< pointer to store the energy of the omega set */
6361  )
6362 {
6363  SCIP_BTNODE* left;
6364  SCIP_BTNODE* right;
6365  SCIP_NODEDATA* nodedata;
6366  SCIP_NODEDATA* leftdata;
6367  SCIP_NODEDATA* rightdata;
6368 
6369  assert(node != NULL);
6370 
6371  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6372  assert(nodedata != NULL);
6373 
6374  /* check if the node is a leaf */
6375  if( SCIPbtnodeIsLeaf(node) )
6376  {
6377  assert(!nodedata->intheta);
6378  return;
6379  }
6380 
6381  left = SCIPbtnodeGetLeftchild(node);
6382  assert(left != NULL);
6383 
6384  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6385  assert(leftdata != NULL);
6386 
6387  right = SCIPbtnodeGetRightchild(node);
6388  assert(right != NULL);
6389 
6390  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6391  assert(rightdata != NULL);
6392 
6393  assert(nodedata->enveloplambda != -1);
6394  assert(rightdata->energytheta != -1);
6395 
6396  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6397  {
6398  traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6399  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6400  }
6401  else
6402  {
6403  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6404  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6405  {
6406  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6407  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6408  }
6409  else
6410  {
6411  assert(rightdata->enveloplambda != -1);
6412  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6413  traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6414  }
6415  }
6416 }
6417 
6418 /** compute the energy contribution by job which corresponds to the given leaf */
6419 static
6421  SCIP_BTNODE* node /**< leaf */
6422  )
6423 {
6424  SCIP_NODEDATA* nodedata;
6425  int duration;
6426 
6427  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6428  assert(nodedata != NULL);
6429  assert(nodedata->var != NULL);
6430 
6431  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6432  assert(duration > 0);
6433 
6434  SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6436  SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6437 
6438  /* return energy which is contributed by the start time variable */
6439  return nodedata->demand * duration;
6440 }
6441 
6442 /** comparison method for two node data w.r.t. the earliest start time */
6443 static
6444 SCIP_DECL_SORTPTRCOMP(compNodeEst)
6446  int est1;
6447  int est2;
6448 
6449  est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6450  est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6451 
6452  return (est1 - est2);
6453 }
6454 
6455 /** comparison method for two node data w.r.t. the latest completion time */
6456 static
6457 SCIP_DECL_SORTINDCOMP(compNodedataLct)
6459  SCIP_NODEDATA* nodedatas;
6460 
6461  nodedatas = (SCIP_NODEDATA*) dataptr;
6462  return (nodedatas[ind1].lct - nodedatas[ind2].lct);
6463 }
6464 
6465 
6466 /** an overload was detected; initialized conflict analysis, add an initial reason
6467  *
6468  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6469  */
6470 static
6472  SCIP* scip, /**< SCIP data structure */
6473  SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6474  int capacity, /**< cumulative capacity */
6475  int nleaves, /**< number of responsible leaves */
6476  int est, /**< earliest start time of the ...... */
6477  int lct, /**< latest completly time of the .... */
6478  int reportedenergy, /**< energy which already reported */
6479  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6480  int shift, /**< shift applied to all jobs before adding them to the tree */
6481  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6482  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6483  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6484  )
6485 {
6486  SCIP_Longint energy;
6487  int j;
6488 
6489  /* do nothing if conflict analysis is not applicable */
6491  return SCIP_OKAY;
6492 
6493  SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6494 
6495  /* compute energy of initial time window */
6496  energy = ((SCIP_Longint) lct - est) * capacity;
6497 
6498  /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6499  SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6500 
6501  /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6502  * thereby, compute the time window of interest
6503  */
6504  for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6505  {
6506  SCIP_NODEDATA* nodedata;
6507 
6508  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6509  assert(nodedata != NULL);
6510 
6511  reportedenergy += computeEnergyContribution(leaves[j]);
6512 
6513  /* adjust energy if the earliest start time decrease */
6514  if( nodedata->est < est )
6515  {
6516  est = nodedata->est;
6517  energy = ((SCIP_Longint) lct - est) * capacity;
6518  }
6519  }
6520  assert(reportedenergy > energy);
6521 
6522  SCIPdebugMsg(scip, "time window [%d,%d) available energy %" SCIP_LONGINT_FORMAT ", required energy %d\n", est, lct, energy, reportedenergy);
6523 
6524  /* initialize conflict analysis */
6526 
6527  /* flip earliest start time and latest completion time */
6528  if( !propest )
6529  {
6530  SCIPswapInts(&est, &lct);
6531 
6532  /* shift earliest start time and latest completion time */
6533  lct = shift - lct;
6534  est = shift - est;
6535  }
6536  else
6537  {
6538  /* shift earliest start time and latest completion time */
6539  lct = lct + shift;
6540  est = est + shift;
6541  }
6542 
6543  nleaves = j;
6544 
6545  /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6546  * overloaded
6547  */
6548  for( j = nleaves-1; j >= 0; --j )
6549  {
6550  SCIP_NODEDATA* nodedata;
6551 
6552  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6553  assert(nodedata != NULL);
6554  assert(nodedata->var != NULL);
6555 
6556  /* check if bound widening should be used */
6557  if( usebdwidening )
6558  {
6559  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6560  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6561  }
6562  else
6563  {
6564  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6565  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6566  }
6567 
6568  if( explanation != NULL )
6569  explanation[nodedata->idx] = TRUE;
6570  }
6571 
6572  (*initialized) = TRUE;
6573 
6574  return SCIP_OKAY;
6575 }
6576 
6577 /** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6578  * responsible interval bounds in *est_omega and *lct_omega
6579  */
6580 static
6581 int computeEstOmegaset(
6582  SCIP* scip, /**< SCIP data structure */
6583  int duration, /**< duration of the job to move */
6584  int demand, /**< demand of the job to move */
6585  int capacity, /**< cumulative capacity */
6586  int est, /**< earliest start time of the omega set */
6587  int lct, /**< latest start time of the omega set */
6588  int energy /**< energy of the omega set */
6589  )
6590 {
6591  int newest;
6592 
6593  newest = 0;
6594 
6595  assert(scip != NULL);
6596 
6597  if( energy > ((SCIP_Longint) capacity - demand) * ((SCIP_Longint) lct - est) )
6598  {
6599  if( energy + (SCIP_Longint) demand * duration > capacity * ((SCIP_Longint) lct - est) )
6600  {
6601  newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6602  newest += est;
6603  }
6604  }
6605 
6606  return newest;
6607 }
6608 
6609 /** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6610  *
6611  * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6612  * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6613  */
6614 static
6616  SCIP* scip, /**< SCIP data structure */
6617  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6618  SCIP_CONS* cons, /**< constraint which is propagated */
6619  SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6620  SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6621  int capacity, /**< cumulative capacity */
6622  int ncands, /**< number of candidates */
6623  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6624  int shift, /**< shift applied to all jobs before adding them to the tree */
6625  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6626  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6627  int* nchgbds, /**< pointer to store the number of bound changes */
6628  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6629  )
6630 {
6631  SCIP_NODEDATA* rootdata;
6632  int j;
6633 
6634  assert(!SCIPbtIsEmpty(tree));
6635 
6636  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6637  assert(rootdata != NULL);
6638 
6639  /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6640  for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6641  {
6642  SCIP_NODEDATA* nodedata;
6643 
6644  if( SCIPbtnodeIsRoot(leaves[j]) )
6645  break;
6646 
6647  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6648  assert(nodedata->est != -1);
6649 
6650  /* check if the root lambda envelop exeeds the available capacity */
6651  while( !(*cutoff) && rootdata->enveloplambda > (SCIP_Longint) capacity * nodedata->lct )
6652  {
6653  SCIP_BTNODE** omegaset;
6654  SCIP_BTNODE* leaf;
6655  SCIP_NODEDATA* leafdata;
6656  int nelements;
6657  int energy;
6658  int newest;
6659  int est;
6660  int lct;
6661 
6662  assert(!(*cutoff));
6663 
6664  /* find responsible leaf for the lambda envelope */
6666  assert(leaf != NULL);
6667  assert(SCIPbtnodeIsLeaf(leaf));
6668 
6669  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6670  assert(leafdata != NULL);
6671  assert(!leafdata->intheta);
6672  assert(leafdata->duration > 0);
6673  assert(leafdata->est >= 0);
6674 
6675  /* check if the job has to be removed since its latest completion is to large */
6676  if( leafdata->est + leafdata->duration >= nodedata->lct )
6677  {
6678  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6679 
6680  /* the root might changed therefore we need to collect the new root node data */
6681  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6682  assert(rootdata != NULL);
6683 
6684  continue;
6685  }
6686 
6687  /* compute omega set */
6688  SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6689 
6690  nelements = 0;
6691  est = INT_MAX;
6692  lct = INT_MIN;
6693  energy = 0;
6694 
6695  /* collect the omega set from theta set */
6696  traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6697  assert(nelements > 0);
6698  assert(nelements < ncands);
6699 
6700  newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6701 
6702  /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6703  if( newest > lct )
6704  {
6705  SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6706 
6707  /* analyze over load */
6708  SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6709  conshdlrdata->usebdwidening, initialized, explanation) );
6710  (*cutoff) = TRUE;
6711 
6712  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6713  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6714  }
6715  else if( newest > 0 )
6716  {
6717  SCIP_Bool infeasible;
6718  SCIP_Bool tightened;
6719  INFERINFO inferinfo;
6720 
6721  if( propest )
6722  {
6723  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6724  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6725 
6726  SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6727  SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6728 
6729  if( inferInfoIsValid(inferinfo) )
6730  {
6731  SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6732  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6733  }
6734  else
6735  {
6736  SCIP_CALL( SCIPtightenVarLb(scip, leafdata->var, (SCIP_Real)(newest + shift),
6737  TRUE, &infeasible, &tightened) );
6738  }
6739 
6740  /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6742  }
6743  else
6744  {
6745  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6746  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6747 
6748  SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6749  SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6750 
6751  if( inferInfoIsValid(inferinfo) )
6752  {
6753  SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6754  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6755  }
6756  else
6757  {
6758  SCIP_CALL( SCIPtightenVarUb(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6759  TRUE, &infeasible, &tightened) );
6760  }
6761 
6762  /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6764  }
6765 
6766  /* adjust the earliest start time */
6767  if( tightened )
6768  {
6769  leafdata->est = newest;
6770  (*nchgbds)++;
6771  }
6772 
6773  if( infeasible )
6774  {
6775  /* initialize conflict analysis if conflict analysis is applicable */
6777  {
6778  int i;
6779 
6780  SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6781 
6783 
6784  /* add lower and upper bound of variable which leads to the infeasibilty */
6785  SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6786  SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6787 
6788  if( explanation != NULL )
6789  explanation[leafdata->idx] = TRUE;
6790 
6791  /* add lower and upper bound of variable which lead to the infeasibilty */
6792  for( i = 0; i < nelements; ++i )
6793  {
6794  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6795  assert(nodedata != NULL);
6796 
6797  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6798  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6799 
6800  if( explanation != NULL )
6801  explanation[nodedata->idx] = TRUE;
6802  }
6803 
6804  (*initialized) = TRUE;
6805  }
6806 
6807  (*cutoff) = TRUE;
6808 
6809  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6810  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6811  }
6812  }
6813 
6814  /* free omegaset array */
6815  SCIPfreeBufferArray(scip, &omegaset);
6816 
6817  /* delete responsible leaf from lambda */
6818  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6819 
6820  /* the root might changed therefore we need to collect the new root node data */
6821  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6822  assert(rootdata != NULL);
6823  }
6824 
6825  /* move current job j from the theta set into the lambda set */
6826  SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6827  }
6828 
6829  return SCIP_OKAY;
6830 }
6831 
6832 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6833  *
6834  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6835  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6836  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6837  */
6838 static
6840  SCIP* scip, /**< SCIP data structure */
6841  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6842  int nvars, /**< number of start time variables (activities) */
6843  SCIP_VAR** vars, /**< array of start time variables */
6844  int* durations, /**< array of durations */
6845  int* demands, /**< array of demands */
6846  int capacity, /**< cumulative capacity */
6847  int hmin, /**< left bound of time axis to be considered (including hmin) */
6848  int hmax, /**< right bound of time axis to be considered (not including hmax) */
6849  SCIP_CONS* cons, /**< constraint which is propagated */
6850  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6851  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6852  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6853  int* nchgbds, /**< pointer to store the number of bound changes */
6854  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6855  )
6856 {
6857  SCIP_NODEDATA* nodedatas;
6858  SCIP_BTNODE** leaves;
6859  SCIP_BT* tree;
6860  int* nodedataidx;
6861 
6862  int totalenergy;
6863  int nnodedatas;
6864  int ninsertcands;
6865  int ncands;
6866 
6867  int shift;
6868  int idx = -1;
6869  int j;
6870 
6871  assert(scip != NULL);
6872  assert(cons != NULL);
6873  assert(initialized != NULL);
6874  assert(cutoff != NULL);
6875  assert(*cutoff == FALSE);
6876 
6877  SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6878 
6879  SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6880  SCIP_CALL( SCIPallocBufferArray(scip, &nodedataidx, 2*nvars) );
6881  SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6882 
6883  ncands = 0;
6884  totalenergy = 0;
6885 
6886  SCIP_CALL( SCIPbtCreate(&tree, SCIPblkmem(scip)) );
6887 
6888  /* compute the shift which we apply to compute .... latest completion time of all jobs */
6889  if( propest )
6890  shift = 0;
6891  else
6892  {
6893  shift = 0;
6894 
6895  /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6896  * earliest start time propagation to handle the latest completion times
6897  */
6898  for( j = 0; j < nvars; ++j )
6899  {
6900  int lct;
6901 
6902  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6903  shift = MAX(shift, lct);
6904  }
6905  }
6906 
6907  /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6908  * horizon
6909  */
6910  for( j = 0; j < nvars; ++j )
6911  {
6912  SCIP_NODEDATA* nodedata;
6913  SCIP_VAR* var;
6914  int duration;
6915  int leftadjust;
6916  int rightadjust;
6917  int energy;
6918  int est;
6919  int lct;
6920 
6921  var = vars[j];
6922  assert(var != NULL);
6923 
6924  duration = durations[j];
6925  assert(duration > 0);
6926 
6927  leftadjust = 0;
6928  rightadjust = 0;
6929 
6930  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
6931  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6932 
6933  /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6934  * effective horizon [hmin,hmax)
6935  */
6936  if( conshdlrdata->useadjustedjobs )
6937  {
6938  if( est < hmin )
6939  {
6940  leftadjust = (hmin - est);
6941  est = hmin;
6942  }
6943  if( lct > hmax )
6944  {
6945  rightadjust = (lct - hmax);
6946  lct = hmax;
6947  }
6948 
6949  /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6950  * with the effective time horizon
6951  */
6952  if( duration - leftadjust - rightadjust <= 0 )
6953  continue;
6954  }
6955  else if( est < hmin || lct > hmax )
6956  continue;
6957 
6958  energy = demands[j] * (duration - leftadjust - rightadjust);
6959  assert(energy > 0);
6960 
6961  totalenergy += energy;
6962 
6963  /* flip earliest start time and latest completion time */
6964  if( !propest )
6965  {
6966  SCIPswapInts(&est, &lct);
6967 
6968  /* shift earliest start time and latest completion time */
6969  lct = shift - lct;
6970  est = shift - est;
6971  }
6972  else
6973  {
6974  /* shift earliest start time and latest completion time */
6975  lct = lct - shift;
6976  est = est - shift;
6977  }
6978  assert(est < lct);
6979  assert(est >= 0);
6980  assert(lct >= 0);
6981 
6982  /* create search node data */
6983  nodedata = &nodedatas[ncands];
6984  nodedataidx[ncands] = ncands;
6985  ++ncands;
6986 
6987  /* initialize search node data */
6988  /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6989  nodedata->key = est + j / (2.0 * nvars);
6990  nodedata->var = var;
6991  nodedata->est = est;
6992  nodedata->lct = lct;
6993  nodedata->demand = demands[j];
6994  nodedata->duration = duration;
6995  nodedata->leftadjust = leftadjust;
6996  nodedata->rightadjust = rightadjust;
6997 
6998  /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6999  * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
7000  * particular time interval [a,b] against the time interval [0,b].
7001  */
7002  nodedata->enveloptheta = (SCIP_Longint) capacity * est + energy;
7003  nodedata->energytheta = energy;
7004  nodedata->enveloplambda = -1;
7005  nodedata->energylambda = -1;
7006 
7007  nodedata->idx = j;
7008  nodedata->intheta = TRUE;
7009  }
7010 
7011  nnodedatas = ncands;
7012 
7013  /* sort (non-decreasing) the jobs w.r.t. latest completion times */
7014  SCIPsortInd(nodedataidx, compNodedataLct, (void*)nodedatas, ncands);
7015 
7016  ninsertcands = 0;
7017 
7018  /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
7019  * the root envelop detects an overload
7020  */
7021  for( j = 0; j < ncands; ++j )
7022  {
7023  SCIP_BTNODE* leaf;
7024  SCIP_NODEDATA* rootdata;
7025 
7026  idx = nodedataidx[j];
7027 
7028  /* check if the new job opens a time window which size is so large that it offers more energy than the total
7029  * energy of all candidate jobs. If so we skip that one.
7030  */
7031  if( ((SCIP_Longint) nodedatas[idx].lct - nodedatas[idx].est) * capacity >= totalenergy )
7032  {
7033  /* set the earliest start time to minus one to mark that candidate to be not used */
7034  nodedatas[idx].est = -1;
7035  continue;
7036  }
7037 
7038  /* create search node */
7039  SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)&nodedatas[idx]) );
7040 
7041  /* insert new node into the theta set and updete the envelops */
7042  SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, nodedataidx, &nnodedatas) );
7043  assert(nnodedatas <= 2*nvars);
7044 
7045  /* move the inserted candidates together */
7046  leaves[ninsertcands] = leaf;
7047  ninsertcands++;
7048 
7049  assert(!SCIPbtIsEmpty(tree));
7050  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
7051  assert(rootdata != NULL);
7052 
7053  /* check if the theta set envelops exceeds the available capacity */
7054  if( rootdata->enveloptheta > (SCIP_Longint) capacity * nodedatas[idx].lct )
7055  {
7056  SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[idx].lct, j);
7057  (*cutoff) = TRUE;
7058 
7059  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
7060  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverload++ );
7061 
7062  break;
7063  }
7064  }
7065 
7066  /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
7067  if( *cutoff )
7068  {
7069  int glbenery;
7070  int est;
7071  int lct;
7072 
7073  glbenery = 0;
7074  assert( 0 <= idx );
7075  est = nodedatas[idx].est;
7076  lct = nodedatas[idx].lct;
7077 
7078  /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
7079  * which led to an overload
7080  */
7081  for( j = j+1; j < ncands; ++j )
7082  {
7083  SCIP_NODEDATA* nodedata;
7084  int duration;
7085  int glbest;
7086  int glblct;
7087 
7088  idx = nodedataidx[j];
7089  nodedata = &nodedatas[idx];
7090  assert(nodedata != NULL);
7091 
7092  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
7093 
7094  /* get latest start time */
7095  glbest = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(nodedata->var));
7096  glblct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
7097 
7098  /* check if parts of the jobs run with the time window defined by the last inserted job */
7099  if( glbest < est )
7100  duration -= (est - glbest);
7101 
7102  if( glblct > lct )
7103  duration -= (glblct - lct);
7104 
7105  if( duration > 0 )
7106  {
7107  glbenery += nodedata->demand * duration;
7108 
7109  if( explanation != NULL )
7110  explanation[nodedata->idx] = TRUE;
7111  }
7112  }
7113 
7114  /* analyze the overload */
7115  SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7116  conshdlrdata->usebdwidening, initialized, explanation) );
7117  }
7118  else if( ninsertcands > 1 && conshdlrdata->efinfer )
7119  {
7120  /* if we have more than one job insterted and edge-finding should be performed we do it */
7121  SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7122  propest, shift, initialized, explanation, nchgbds, cutoff) );
7123  }
7124 
7125  /* free theta tree */
7126  SCIPbtFree(&tree);
7127 
7128  /* free buffer arrays */
7129  SCIPfreeBufferArray(scip, &leaves);
7130  SCIPfreeBufferArray(scip, &nodedataidx);
7131  SCIPfreeBufferArray(scip, &nodedatas);
7132 
7133  return SCIP_OKAY;
7134 }
7135 
7136 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7137  *
7138  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7139  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7140  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7141  */
7142 static
7144  SCIP* scip, /**< SCIP data structure */
7145  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7146  int nvars, /**< number of start time variables (activities) */
7147  SCIP_VAR** vars, /**< array of start time variables */
7148  int* durations, /**< array of durations */
7149  int* demands, /**< array of demands */
7150  int capacity, /**< cumulative capacity */
7151  int hmin, /**< left bound of time axis to be considered (including hmin) */
7152  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7153  SCIP_CONS* cons, /**< constraint which is propagated */
7154  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7155  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7156  int* nchgbds, /**< pointer to store the number of bound changes */
7157  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7158  )
7159 {
7160  /* check if a cutoff was already detected */
7161  if( (*cutoff) )
7162  return SCIP_OKAY;
7163 
7164  /* check if at least the basic overload checking should be preformed */
7165  if( !conshdlrdata->efcheck )
7166  return SCIP_OKAY;
7167 
7168  /* check for overload, which may result in a cutoff */
7169  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7170  cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7171 
7172  /* check if a cutoff was detected */
7173  if( (*cutoff) )
7174  return SCIP_OKAY;
7175 
7176  /* check if bound should be infer */
7177  if( !conshdlrdata->efinfer )
7178  return SCIP_OKAY;
7179 
7180  /* check for overload, which may result in a cutoff */
7181  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7182  cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7183 
7184  return SCIP_OKAY;
7185 }
7186 
7187 /** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7188  * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7189  * event points
7190  */
7191 static
7193  SCIP* scip, /**< SCIP data structure */
7194  int nvars, /**< number of start time variables (activities) */
7195  SCIP_VAR** vars, /**< array of start time variables */
7196  int* durations, /**< array of durations */
7197  int* demands, /**< array of demands */
7198  int capacity, /**< cumulative capacity */
7199  int hmin, /**< left bound of time axis to be considered (including hmin) */
7200  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7201  SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7202  )
7203 {
7204  SCIP_VAR* var;
7205  int* starttimes; /* stores when each job is starting */
7206  int* endtimes; /* stores when each job ends */
7207  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7208  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7209 
7210  int lb;
7211  int ub;
7212  int freecapacity; /* remaining capacity */
7213  int curtime; /* point in time which we are just checking */
7214  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7215  int njobs;
7216  int j;
7217 
7218  assert(scip != NULL);
7219  assert(redundant != NULL);
7220 
7221  (*redundant) = TRUE;
7222 
7223  /* if no activities are associated with this cumulative then this constraint is redundant */
7224  if( nvars == 0 )
7225  return SCIP_OKAY;
7226 
7227  assert(vars != NULL);
7228 
7229  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7230  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7231  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7232  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7233 
7234  njobs = 0;
7235 
7236  /* assign variables, start and endpoints to arrays */
7237  for( j = 0; j < nvars; ++j )
7238  {
7239  assert(durations[j] > 0);
7240  assert(demands[j] > 0);
7241 
7242  var = vars[j];
7243  assert(var != NULL);
7244 
7245  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7246  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7247 
7248  /* check if jobs runs completely outside of the effective time horizon */
7249  if( lb >= hmax || ub + durations[j] <= hmin )
7250  continue;
7251 
7252  starttimes[njobs] = MAX(lb, hmin);
7253  startindices[njobs] = j;
7254 
7255  endtimes[njobs] = MIN(ub + durations[j], hmax);
7256  endindices[njobs] = j;
7257  assert(starttimes[njobs] <= endtimes[njobs]);
7258  njobs++;
7259  }
7260 
7261  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7262  SCIPsortIntInt(starttimes, startindices, njobs);
7263  SCIPsortIntInt(endtimes, endindices, njobs);
7264 
7265  endindex = 0;
7266  freecapacity = capacity;
7267 
7268  /* check each start point of a job whether the capacity is violated or not */
7269  for( j = 0; j < njobs; ++j )
7270  {
7271  curtime = starttimes[j];
7272 
7273  /* stop checking, if time point is above hmax */
7274  if( curtime >= hmax )
7275  break;
7276 
7277  /* subtract all capacity needed up to this point */
7278  freecapacity -= demands[startindices[j]];
7279  while( j+1 < njobs && starttimes[j+1] == curtime )
7280  {
7281  ++j;
7282  freecapacity -= demands[startindices[j]];
7283  }
7284 
7285  /* free all capacity usages of jobs the are no longer running */
7286  while( endtimes[endindex] <= curtime )
7287  {
7288  freecapacity += demands[endindices[endindex]];
7289  ++endindex;
7290  }
7291  assert(freecapacity <= capacity);
7292 
7293  /* check freecapacity to be smaller than zero */
7294  if( freecapacity < 0 && curtime >= hmin )
7295  {
7296  (*redundant) = FALSE;
7297  break;
7298  }
7299  } /*lint --e{850}*/
7300 
7301  /* free all buffer arrays */
7302  SCIPfreeBufferArray(scip, &endindices);
7303  SCIPfreeBufferArray(scip, &startindices);
7304  SCIPfreeBufferArray(scip, &endtimes);
7305  SCIPfreeBufferArray(scip, &starttimes);
7306 
7307  return SCIP_OKAY;
7308 }
7309 
7310 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7311  * completion time
7312  */
7313 static
7315  SCIP* scip, /**< SCIP data structure */
7316  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7317  SCIP_PROFILE* profile, /**< resource profile */
7318  int nvars, /**< number of variables (jobs) */
7319  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7320  int* durations, /**< array containing corresponding durations */
7321  int* demands, /**< array containing corresponding demands */
7322  int capacity, /**< cumulative capacity */
7323  int hmin, /**< left bound of time axis to be considered (including hmin) */
7324  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7325  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7326  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7327  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7328  )
7329 {
7330  int v;
7331 
7332  /* insert all cores */
7333  for( v = 0; v < nvars; ++v )
7334  {
7335  SCIP_VAR* var;
7336  SCIP_Bool infeasible;
7337  int duration;
7338  int demand;
7339  int begin;
7340  int end;
7341  int est;
7342  int lst;
7343  int pos;
7344 
7345  var = vars[v];
7346  assert(var != NULL);
7347  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(var)));
7348  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(var)));
7349 
7350  duration = durations[v];
7351  assert(duration > 0);
7352 
7353  demand = demands[v];
7354  assert(demand > 0);
7355 
7356  /* collect earliest and latest start time */
7357  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7358  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7359 
7360  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7361  if( lst + duration <= hmin || est >= hmax )
7362  continue;
7363 
7364  /* compute core interval w.r.t. effective time horizon */
7365  begin = MAX(hmin, lst);
7366  end = MIN(hmax, est + duration);
7367 
7368  /* check if a core exists */
7369  if( begin >= end )
7370  continue;
7371 
7372  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7373  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7374 
7375  /* insert the core into core resource profile (complexity O(log n)) */
7376  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7377 
7378  /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7379  if( infeasible )
7380  {
7381  assert(begin <= SCIPprofileGetTime(profile, pos));
7382  assert(end > SCIPprofileGetTime(profile, pos));
7383 
7384  /* use conflict analysis to analysis the core insertion which was infeasible */
7385  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7386  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7387 
7388  if( explanation != NULL )
7389  explanation[v] = TRUE;
7390 
7391  (*cutoff) = TRUE;
7392 
7393  /* for the statistic we count the number of times a cutoff was detected due the time-time */
7394  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
7395 
7396  break;
7397  }
7398  }
7399 
7400  return SCIP_OKAY;
7401 }
7402 
7403 /** propagate the cumulative condition */
7404 static
7406  SCIP* scip, /**< SCIP data structure */
7407  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7408  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7409  int nvars, /**< number of start time variables (activities) */
7410  SCIP_VAR** vars, /**< array of start time variables */
7411  int* durations, /**< array of durations */
7412  int* demands, /**< array of demands */
7413  int capacity, /**< cumulative capacity */
7414  int hmin, /**< left bound of time axis to be considered (including hmin) */
7415  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7416  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7417  int* nchgbds, /**< pointer to store the number of bound changes */
7418  SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7419  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7420  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7421  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7422  )
7423 {
7424  SCIP_PROFILE* profile;
7425 
7426  SCIP_RETCODE retcode = SCIP_OKAY;
7427 
7428  assert(nchgbds != NULL);
7429  assert(initialized != NULL);
7430  assert(cutoff != NULL);
7431  assert(!(*cutoff));
7432 
7433  /**@todo avoid always sorting the variable array */
7434 
7435  /* check if the constraint is redundant */
7436  SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7437 
7438  if( *redundant )
7439  return SCIP_OKAY;
7440 
7441  /* create an empty resource profile for profiling the cores of the jobs */
7442  SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7443 
7444  /* create core profile (compulsory parts) */
7445  SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7446  initialized, explanation, cutoff), TERMINATE );
7447 
7448  /* propagate the job cores until nothing else can be detected */
7449  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7450  {
7451  SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7452  nchgbds, initialized, explanation, cutoff), TERMINATE );
7453  }
7454 
7455  /* run edge finding propagator */
7456  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7457  {
7458  SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7459  cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7460  }
7461 
7462  /* run time-table edge-finding propagator */
7463  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7464  {
7465  SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7466  nchgbds, initialized, explanation, cutoff), TERMINATE );
7467  }
7468  /* free resource profile */
7469 TERMINATE:
7470  SCIPprofileFree(&profile);
7471 
7472  return retcode;
7473 }
7474 
7475 /** propagate the cumulative constraint */
7476 static
7478  SCIP* scip, /**< SCIP data structure */
7479  SCIP_CONS* cons, /**< constraint to propagate */
7480  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7481  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7482  int* nchgbds, /**< pointer to store the number of bound changes */
7483  int* ndelconss, /**< pointer to store the number of deleted constraints */
7484  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7485  )
7486 {
7487  SCIP_CONSDATA* consdata;
7488  SCIP_Bool initialized;
7489  SCIP_Bool redundant;
7490  int oldnchgbds;
7491 
7492  assert(scip != NULL);
7493  assert(cons != NULL);
7494 
7495  consdata = SCIPconsGetData(cons);
7496  assert(consdata != NULL);
7497 
7498  oldnchgbds = *nchgbds;
7499  initialized = FALSE;
7500  redundant = FALSE;
7501 
7502  if( SCIPconsIsDeleted(cons) )
7503  {
7504  assert(SCIPinProbing(scip));
7505  return SCIP_OKAY;
7506  }
7507 
7508  /* if the constraint marked to be propagated, do nothing */
7509  if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7510  return SCIP_OKAY;
7511 
7512  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7513  consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7514  consdata->hmin, consdata->hmax, cons,
7515  nchgbds, &redundant, &initialized, NULL, cutoff) );
7516 
7517  if( redundant )
7518  {
7519  SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7520  SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7521 
7522  if( !SCIPinProbing(scip) )
7523  {
7524  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7525  (*ndelconss)++;
7526  }
7527  }
7528  else
7529  {
7530  if( initialized )
7531  {
7532  /* run conflict analysis since it was initialized */
7533  assert(*cutoff == TRUE);
7534  SCIPdebugMsg(scip, "start conflict analysis\n");
7535  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7536  }
7537 
7538  /* if successful, reset age of constraint */
7539  if( *cutoff || *nchgbds > oldnchgbds )
7540  {
7541  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7542  }
7543  else
7544  {
7545  /* mark the constraint to be propagated */
7546  consdata->propagated = TRUE;
7547  }
7548  }
7549 
7550  return SCIP_OKAY;
7551 }
7552 
7553 /** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7554  * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7555  * be realize as domain reduction. Otherwise we do nothing
7556  */
7557 static
7559  SCIP* scip, /**< SCIP data structure */
7560  SCIP_VAR** vars, /**< problem variables */
7561  int nvars, /**< number of problem variables */
7562  int probingpos, /**< variable number to apply probing on */
7563  SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7564  SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7565  SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7566  SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7567  SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7568  SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7569  SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7570  SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7571  SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7572  SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7573  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7574  SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7575  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7576  )
7577 {
7578  SCIP_VAR* var;
7579  SCIP_Bool tightened;
7580 
7581  assert(probingpos >= 0);
7582  assert(probingpos < nvars);
7583  assert(success != NULL);
7584  assert(cutoff != NULL);
7585 
7586  var = vars[probingpos];
7587  assert(var != NULL);
7588  assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7589  assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7590  assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7591  assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7592 
7593  (*success) = FALSE;
7594 
7595  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7596  return SCIP_OKAY;
7597 
7598  /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7599  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7600  leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7601 
7602  if( (*cutoff) )
7603  {
7604  /* note that cutoff may occur if presolving has not been executed fully */
7605  SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7606 
7607  if( tightened )
7608  {
7609  (*success) =TRUE;
7610  (*nfixedvars)++;
7611  }
7612 
7613  return SCIP_OKAY;
7614  }
7615 
7616  /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7617  * presolving has not been executed fully
7618  */
7619  if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7620  {
7621  /* note that cutoff may occur if presolving has not been executed fully */
7622  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7623 
7624  if( tightened )
7625  {
7626  (*success) = TRUE;
7627  (*nfixedvars)++;
7628  }
7629 
7630  return SCIP_OKAY;
7631  }
7632 
7633  /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7634  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7635  rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7636 
7637  if( (*cutoff) )
7638  {
7639  /* note that cutoff may occur if presolving has not been executed fully */
7640  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7641 
7642  if( tightened )
7643  {
7644  (*success) =TRUE;
7645  (*nfixedvars)++;
7646  }
7647 
7648  return SCIP_OKAY;
7649  }
7650 
7651  return SCIP_OKAY;
7652 }
7653 
7654 /** is it possible, to round variable down w.r.t. objective function */
7655 static
7657  SCIP* scip, /**< SCIP data structure */
7658  SCIP_VAR* var, /**< problem variable */
7659  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7660  )
7661 {
7662  SCIP_Real objval;
7663  int scalar;
7664 
7665  assert(roundable != NULL);
7666 
7667  *roundable = TRUE;
7668 
7669  /* a fixed variable can be definition always be safely rounded */
7671  return SCIP_OKAY;
7672 
7673  /* in case the variable is not active we need to check the object coefficient of the active variable */
7674  if( !SCIPvarIsActive(var) )
7675  {
7676  SCIP_VAR* actvar;
7677  int constant;
7678 
7679  actvar = var;
7680 
7681  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7682  assert(scalar != 0);
7683 
7684  objval = scalar * SCIPvarGetObj(actvar);
7685  } /*lint !e438*/
7686  else
7687  {
7688  scalar = 1;
7689  objval = SCIPvarGetObj(var);
7690  }
7691 
7692  /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7693  * (the transformed problem is always a minimization problem)
7694  *
7695  * @note that we need to check this condition w.r.t. active variable space
7696  */
7697  if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7698  *roundable = FALSE;
7699 
7700  return SCIP_OKAY;
7701 }
7702 
7703 /** is it possible, to round variable up w.r.t. objective function */
7704 static
7706  SCIP* scip, /**< SCIP data structure */
7707  SCIP_VAR* var, /**< problem variable */
7708  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7709  )
7710 {
7711  SCIP_Real objval;
7712  int scalar;
7713 
7714  assert(roundable != NULL);
7715 
7716  *roundable = TRUE;
7717 
7718  /* a fixed variable can be definition always be safely rounded */
7720  return SCIP_OKAY;
7721 
7722  /* in case the variable is not active we need to check the object coefficient of the active variable */
7723  if( !SCIPvarIsActive(var) )
7724  {
7725  SCIP_VAR* actvar;
7726  int constant;
7727 
7728  actvar = var;
7729 
7730  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7731  assert(scalar != 0);
7732 
7733  objval = scalar * SCIPvarGetObj(actvar);
7734  } /*lint !e438*/
7735  else
7736  {
7737  scalar = 1;
7738  objval = SCIPvarGetObj(var);
7739  }
7740 
7741  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7742  * (the transformed problem is always a minimization problem)
7743  *
7744  * @note that we need to check this condition w.r.t. active variable space
7745  */
7746  if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7747  *roundable = FALSE;
7748 
7749  return SCIP_OKAY;
7750 }
7751 
7752 /** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7753  * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7754  * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7755  * the only one locking this variable in the corresponding direction.
7756  */
7757 static
7759  SCIP* scip, /**< SCIP data structure */
7760  SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7761  int nconss, /**< number of cumulative constraints */
7762  SCIP_Bool local, /**< use local bounds effective horizon? */
7763  int* alternativelbs, /**< alternative lower bounds */
7764  int* alternativeubs, /**< alternative lower bounds */
7765  int* downlocks, /**< number of constraints with down lock participating by the computation */
7766  int* uplocks /**< number of constraints with up lock participating by the computation */
7767  )
7768 {
7769  int nvars;
7770  int c;
7771  int v;
7772 
7773  for( c = 0; c < nconss; ++c )
7774  {
7775  SCIP_CONSDATA* consdata;
7776  SCIP_CONS* cons;
7777  SCIP_VAR* var;
7778  int hmin;
7779  int hmax;
7780 
7781  cons = conss[c];
7782  assert(cons != NULL);
7783 
7784  /* ignore constraints which are already deletet and those which are not check constraints */
7785  if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7786  continue;
7787 
7788  consdata = SCIPconsGetData(cons);
7789  assert(consdata != NULL);
7790  assert(consdata->nvars > 1);
7791 
7792  /* compute the hmin and hmax */
7793  if( local )
7794  {
7795  SCIP_PROFILE* profile;
7796  SCIP_RETCODE retcode;
7797 
7798  /* create empty resource profile with infinity resource capacity */
7799  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7800 
7801  /* create worst case resource profile */
7802  retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
7803 
7804  hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7805  hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7806 
7807  /* free worst case profile */
7808  SCIPprofileFree(&profile);
7809 
7810  if( retcode != SCIP_OKAY )
7811  return retcode;
7812  }
7813  else
7814  {
7815  hmin = consdata->hmin;
7816  hmax = consdata->hmax;
7817  }
7818 
7819  consdata = SCIPconsGetData(cons);
7820  assert(consdata != NULL);
7821 
7822  nvars = consdata->nvars;
7823 
7824  for( v = 0; v < nvars; ++v )
7825  {
7826  int scalar;
7827  int constant;
7828  int idx;
7829 
7830  var = consdata->vars[v];
7831  assert(var != NULL);
7832 
7833  /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7834  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR);
7835 
7836  /* ignore variable locally fixed variables */
7837  if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7838  continue;
7839 
7840  SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7841  idx = SCIPvarGetProbindex(var);
7842  assert(idx >= 0);
7843 
7844  /* first check lower bound fixing */
7845  if( consdata->downlocks[v] )
7846  {
7847  int ect;
7848  int est;
7849 
7850  /* the variable has a down locked */
7851  est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7852  ect = est + consdata->durations[v];
7853 
7854  if( ect <= hmin || hmin >= hmax )
7855  downlocks[idx]++;
7856  else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7857  {
7858  alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7859  downlocks[idx]++;
7860  }
7861  }
7862 
7863  /* second check upper bound fixing */
7864  if( consdata->uplocks[v] )
7865  {
7866  int duration;
7867  int lct;
7868  int lst;
7869 
7870  duration = consdata->durations[v];
7871 
7872  /* the variable has a up lock locked */
7873  lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7874  lct = lst + duration;
7875 
7876  if( lst >= hmax || hmin >= hmax )
7877  uplocks[idx]++;
7878  else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7879  {
7880  alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7881  uplocks[idx]++;
7882  }
7883  }
7884  }
7885  }
7886 
7887  return SCIP_OKAY;
7888 }
7889 
7890 /** apply all fixings which are given by the alternative bounds */
7891 static
7893  SCIP* scip, /**< SCIP data structure */
7894  SCIP_VAR** vars, /**< array of active variables */
7895  int nvars, /**< number of active variables */
7896  int* alternativelbs, /**< alternative lower bounds */
7897  int* alternativeubs, /**< alternative lower bounds */
7898  int* downlocks, /**< number of constraints with down lock participating by the computation */
7899  int* uplocks, /**< number of constraints with up lock participating by the computation */
7900  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7901  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7902  )
7903 {
7904  SCIP_Real* downimpllbs;
7905  SCIP_Real* downimplubs;
7906  SCIP_Real* downproplbs;
7907  SCIP_Real* downpropubs;
7908  SCIP_Real* upimpllbs;
7909  SCIP_Real* upimplubs;
7910  SCIP_Real* upproplbs;
7911  SCIP_Real* uppropubs;
7912  int v;
7913 
7914  /* get temporary memory for storing probing results */
7915  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7916  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7917  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7918  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7919  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7920  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7921  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7922  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7923 
7924  for( v = 0; v < nvars; ++v )
7925  {
7926  SCIP_VAR* var;
7927  SCIP_Bool infeasible;
7928  SCIP_Bool fixed;
7929  SCIP_Bool roundable;
7930  int ub;
7931  int lb;
7932 
7933  var = vars[v];
7934  assert(var != NULL);
7935 
7936  /* ignore variables for which no alternative bounds have been computed */
7937  if( alternativelbs[v] == INT_MAX && alternativeubs[v] == INT_MIN )
7938  continue;
7939 
7940  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7941  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7942 
7943  /* ignore fixed variables */
7944  if( ub - lb <= 0 )
7945  continue;
7946 
7947  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
7948  {
7949  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7950 
7951  if( roundable )
7952  {
7953  if( alternativelbs[v] > ub )
7954  {
7955  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7956  assert(!infeasible);
7957  assert(fixed);
7958 
7959  (*nfixedvars)++;
7960 
7961  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7962  * constraints
7963  */
7964  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7965  }
7966  else
7967  {
7968  SCIP_Bool success;
7969 
7970  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7971  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7972  * infeasible we can apply the dual reduction; otherwise we do nothing
7973  */
7974  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7975  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7976  nfixedvars, &success, cutoff) );
7977 
7978  if( success )
7979  {
7980  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7981  }
7982  }
7983  }
7984  }
7985 
7986  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7987  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7988 
7989  /* ignore fixed variables */
7990  if( ub - lb <= 0 )
7991  continue;
7992 
7993  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
7994  {
7995  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7996 
7997  if( roundable )
7998  {
7999  if( alternativeubs[v] < lb )
8000  {
8001  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
8002  assert(!infeasible);
8003  assert(fixed);
8004 
8005  (*nfixedvars)++;
8006 
8007  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
8008  * constraints
8009  */
8010  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
8011  }
8012  else
8013  {
8014  SCIP_Bool success;
8015 
8016  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
8017  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
8018  * infeasible we can apply the dual reduction; otherwise we do nothing
8019  */
8020  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
8021  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
8022  nfixedvars, &success, cutoff) );
8023 
8024  if( success )
8025  {
8026  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
8027  }
8028  }
8029  }
8030  }
8031  }
8032 
8033  /* free temporary memory */
8034  SCIPfreeBufferArray(scip, &uppropubs);
8035  SCIPfreeBufferArray(scip, &upproplbs);
8036  SCIPfreeBufferArray(scip, &upimplubs);
8037  SCIPfreeBufferArray(scip, &upimpllbs);
8038  SCIPfreeBufferArray(scip, &downpropubs);
8039  SCIPfreeBufferArray(scip, &downproplbs);
8040  SCIPfreeBufferArray(scip, &downimplubs);
8041  SCIPfreeBufferArray(scip, &downimpllbs);
8042 
8043  return SCIP_OKAY;
8044 }
8045 
8046 /** propagate all constraints together */
8047 static
8049  SCIP* scip, /**< SCIP data structure */
8050  SCIP_CONS** conss, /**< all cumulative constraint */
8051  int nconss, /**< number of cumulative constraints */
8052  SCIP_Bool local, /**< use local bounds effective horizon? */
8053  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
8054  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
8055  SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
8056  )
8057 { /*lint --e{715}*/
8058  SCIP_VAR** vars;
8059  int* downlocks;
8060  int* uplocks;
8061  int* alternativelbs;
8062  int* alternativeubs;
8063  int oldnfixedvars;
8064  int nvars;
8065  int v;
8066 
8067  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
8068  return SCIP_OKAY;
8069 
8070  nvars = SCIPgetNVars(scip);
8071  oldnfixedvars = *nfixedvars;
8072 
8073  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
8074  SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
8075  SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
8076  SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
8077  SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
8078 
8079  /* initialize arrays */
8080  for( v = 0; v < nvars; ++v )
8081  {
8082  downlocks[v] = 0;
8083  uplocks[v] = 0;
8084  alternativelbs[v] = INT_MAX;
8085  alternativeubs[v] = INT_MIN;
8086  }
8087 
8088  /* compute alternative bounds */
8089  SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
8090 
8091  /* apply fixing which result of the alternative bounds directly */
8092  SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
8093  nfixedvars, cutoff) );
8094 
8095  if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
8096  {
8097  SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
8098  }
8099 
8100  /* free all buffers */
8101  SCIPfreeBufferArray(scip, &alternativeubs);
8102  SCIPfreeBufferArray(scip, &alternativelbs);
8103  SCIPfreeBufferArray(scip, &uplocks);
8104  SCIPfreeBufferArray(scip, &downlocks);
8105  SCIPfreeBufferArray(scip, &vars);
8106 
8107  return SCIP_OKAY;
8108 }
8109 
8110 /**@} */
8111 
8112 /**@name Linear relaxations
8113  *
8114  * @{
8115  */
8116 
8117 /** creates covering cuts for jobs violating resource constraints */
8118 static
8120  SCIP* scip, /**< SCIP data structure */
8121  SCIP_CONS* cons, /**< constraint to be checked */
8122  int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8123  int time /**< at this point in time covering constraints are valid */
8124  )
8125 {
8126  SCIP_CONSDATA* consdata;
8127  SCIP_ROW* row;
8128  int* flexibleids;
8129  int* demands;
8130 
8131  char rowname[SCIP_MAXSTRLEN];
8132 
8133  int remainingcap;
8134  int smallcoversize; /* size of a small cover */
8135  int bigcoversize; /* size of a big cover */
8136  int nvars;
8137 
8138  int nflexible;
8139  int sumdemand; /* demand of all jobs up to a certain index */
8140  int j;
8141 
8142  assert(cons != NULL);
8143 
8144  /* get constraint data structure */
8145  consdata = SCIPconsGetData(cons);
8146  assert(consdata != NULL );
8147 
8148  nvars = consdata->nvars;
8149 
8150  /* sort jobs according to demands */
8151  SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8152  SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8153 
8154  nflexible = 0;
8155  remainingcap = consdata->capacity;
8156 
8157  /* get all jobs intersecting point 'time' with their bounds */
8158  for( j = 0; j < nvars; ++j )
8159  {
8160  int ub;
8161 
8162  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8163 
8164  /* only add jobs to array if they intersect with point 'time' */
8165  if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8166  {
8167  /* if job is fixed, capacity has to be decreased */
8168  if( startvalues[j] == ub )
8169  {
8170  remainingcap -= consdata->demands[j];
8171  }
8172  else
8173  {
8174  demands[nflexible] = consdata->demands[j];
8175  flexibleids[nflexible] = j;
8176  ++nflexible;
8177  }
8178  }
8179  }
8180  assert(remainingcap >= 0);
8181 
8182  /* sort demands and job ids */
8183  SCIPsortIntInt(demands, flexibleids, nflexible);
8184 
8185  /*
8186  * version 1:
8187  * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8188  * erzeuge cover constraint
8189  *
8190  */
8191 
8192  /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8193  sumdemand = 0;
8194  j = 0;
8195 
8196  while( j < nflexible && sumdemand <= remainingcap )
8197  {
8198  sumdemand += demands[j];
8199  j++;
8200  }
8201 
8202  /* j jobs form a conflict, set coversize to 'j - 1' */
8203  bigcoversize = j-1;
8204  assert(sumdemand > remainingcap);
8205  assert(bigcoversize < nflexible);
8206 
8207  /* - create a row for all jobs and their binary variables.
8208  * - at most coversize many binary variables of jobs can be set to one
8209  */
8210 
8211  /* construct row name */
8212  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8213  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8214  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8215  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8216 
8217  for( j = 0; j < nflexible; ++j )
8218  {
8219  SCIP_VAR** binvars;
8220  SCIP_Real* vals;
8221  int nbinvars;
8222  int idx;
8223  int start;
8224  int end;
8225  int lb;
8226  int ub;
8227  int b;
8228 
8229  idx = flexibleids[j];
8230 
8231  /* get and add binvars into var array */
8232  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8233  assert(nbinvars != 0);
8234 
8235  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8236  assert(vals != NULL);
8237 
8238  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8239  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8240 
8241  /* compute start and finishing time */
8242  start = time - consdata->durations[idx] + 1;
8243  end = MIN(time, ub);
8244 
8245  /* add all neccessary binary variables */
8246  for( b = 0; b < nbinvars; ++b )
8247  {
8248  if( vals[b] < start || vals[b] < lb )
8249  continue;
8250 
8251  if( vals[b] > end )
8252  break;
8253 
8254  assert(binvars[b] != NULL);
8255  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8256  }
8257  }
8258 
8259  /* insert and release row */
8260  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8261 
8262  if( consdata->bcoverrowssize == 0 )
8263  {
8264  consdata->bcoverrowssize = 10;
8265  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8266  }
8267  if( consdata->nbcoverrows == consdata->bcoverrowssize )
8268  {
8269  consdata->bcoverrowssize *= 2;
8270  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8271  }
8272 
8273  consdata->bcoverrows[consdata->nbcoverrows] = row;
8274  consdata->nbcoverrows++;
8275 
8276  /*
8277  * version 2:
8278  * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8279  * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8280  */
8281  /* find maximum number of jobs that can run in parallel (= coversize -1) */
8282  sumdemand = 0;
8283  j = nflexible -1;
8284  while( sumdemand <= remainingcap )
8285  {
8286  assert(j >= 0);
8287  sumdemand += demands[j];
8288  j--;
8289  }
8290 
8291  smallcoversize = nflexible - (j + 1) - 1;
8292  while( j > 0 && demands[j] == demands[nflexible-1] )
8293  --j;
8294 
8295  assert(smallcoversize < nflexible);
8296 
8297  if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8298  {
8299  /* construct row name */
8300  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8301  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8302  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8303  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8304 
8305  /* filter binary variables for each unfixed job */
8306  for( j = j + 1; j < nflexible; ++j )
8307  {
8308  SCIP_VAR** binvars;
8309  SCIP_Real* vals;
8310  int nbinvars;
8311  int idx;
8312  int start;
8313  int end;
8314  int lb;
8315  int ub;
8316  int b;
8317 
8318  idx = flexibleids[j];
8319 
8320  /* get and add binvars into var array */
8321  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8322  assert(nbinvars != 0);
8323 
8324  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8325  assert(vals != NULL);
8326 
8327  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8328  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8329 
8330  /* compute start and finishing time */
8331  start = time - consdata->durations[idx] + 1;
8332  end = MIN(time, ub);
8333 
8334  /* add all neccessary binary variables */
8335  for( b = 0; b < nbinvars; ++b )
8336  {
8337  if( vals[b] < start || vals[b] < lb )
8338  continue;
8339 
8340  if( vals[b] > end )
8341  break;
8342 
8343  assert(binvars[b] != NULL);
8344  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8345  }
8346  }
8347 
8348  /* insert and release row */
8349  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8350  if( consdata->scoverrowssize == 0 )
8351  {
8352  consdata->scoverrowssize = 10;
8353  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8354  }
8355  if( consdata->nscoverrows == consdata->scoverrowssize )
8356  {
8357  consdata->scoverrowssize *= 2;
8358  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8359  }
8360 
8361  consdata->scoverrows[consdata->nscoverrows] = row;
8362  consdata->nscoverrows++;
8363  }
8364 
8365  /* free buffer arrays */
8366  SCIPfreeBufferArray(scip, &flexibleids);
8367  SCIPfreeBufferArray(scip, &demands);
8368 
8369  return SCIP_OKAY;
8370 }
8371 
8372 /** method to construct cover cuts for all points in time */
8373 static
8375  SCIP* scip, /**< SCIP data structure */
8376  SCIP_CONS* cons /**< constraint to be separated */
8377  )
8378 {
8379  SCIP_CONSDATA* consdata;
8380 
8381  int* startvalues; /* stores when each job is starting */
8382  int* endvalues; /* stores when each job ends */
8383  int* startvaluessorted; /* stores when each job is starting */
8384  int* endvaluessorted; /* stores when each job ends */
8385  int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8386  int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8387 
8388  int nvars; /* number of jobs for this constraint */
8389  int freecapacity; /* remaining capacity */
8390  int curtime; /* point in time which we are just checking */
8391  int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8392 
8393  int hmin;
8394  int hmax;
8395 
8396  int j;
8397  int t;
8398 
8399  assert(scip != NULL);
8400  assert(cons != NULL);
8401 
8402  consdata = SCIPconsGetData(cons);
8403  assert(consdata != NULL);
8404 
8405  /* if no activities are associated with this resource then this constraint is redundant */
8406  if( consdata->vars == NULL )
8407  return SCIP_OKAY;
8408 
8409  nvars = consdata->nvars;
8410  hmin = consdata->hmin;
8411  hmax = consdata->hmax;
8412 
8413  SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8414  SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8415  SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8416  SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8417  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8418  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8419 
8420  /* assign start and endpoints to arrays */
8421  for ( j = 0; j < nvars; ++j )
8422  {
8423  startvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8424  startvaluessorted[j] = startvalues[j];
8425 
8426  endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8427  endvaluessorted[j] = endvalues[j];
8428 
8429  startindices[j] = j;
8430  endindices[j] = j;
8431  }
8432 
8433  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8434  * (and sort the indices in the same way) */
8435  SCIPsortIntInt(startvaluessorted, startindices, nvars);
8436  SCIPsortIntInt(endvaluessorted, endindices, nvars);
8437 
8438  endidx = 0;
8439  freecapacity = consdata->capacity;
8440 
8441  /* check each startpoint of a job whether the capacity is kept or not */
8442  for( j = 0; j < nvars; ++j )
8443  {
8444  curtime = startvaluessorted[j];
8445  if( curtime >= hmax )
8446  break;
8447 
8448  /* subtract all capacity needed up to this point */
8449  freecapacity -= consdata->demands[startindices[j]];
8450 
8451  while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8452  {
8453  ++j;
8454  freecapacity -= consdata->demands[startindices[j]];
8455  }
8456 
8457  /* free all capacity usages of jobs the are no longer running */
8458  while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8459  {
8460  freecapacity += consdata->demands[endindices[endidx]];
8461  ++endidx;
8462  }
8463 
8464  assert(freecapacity <= consdata->capacity);
8465  assert(endidx <= nvars);
8466 
8467  /* --> endindex - points to the next job which will finish
8468  * j - points to the last job that has been released
8469  */
8470 
8471  /* check freecapacity to be smaller than zero
8472  * then we will add cover constraints to the MIP
8473  */
8474  if( freecapacity < 0 && curtime >= hmin )
8475  {
8476  int nextprofilechange;
8477 
8478  /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8479  if( j < nvars-1 )
8480  nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8481  else
8482  nextprofilechange = endvaluessorted[endidx];
8483 
8484  nextprofilechange = MIN(nextprofilechange, hmax);
8485 
8486  for( t = curtime; t < nextprofilechange; ++t )
8487  {
8488  SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8489 
8490  /* create covering constraint */
8491  SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8492  }
8493  } /* end if freecapacity > 0 */
8494  } /*lint --e{850}*/
8495 
8496  consdata->covercuts = TRUE;
8497 
8498  /* free all buffer arrays */
8499  SCIPfreeBufferArray(scip, &endindices);
8500  SCIPfreeBufferArray(scip, &startindices);
8501  SCIPfreeBufferArray(scip, &endvaluessorted);
8502  SCIPfreeBufferArray(scip, &startvaluessorted);
8503  SCIPfreeBufferArray(scip, &endvalues);
8504  SCIPfreeBufferArray(scip, &startvalues);
8505 
8506  return SCIP_OKAY;
8507 }
8508 
8509 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8510  * constraint
8511  */
8512 static
8514  SCIP* scip, /**< SCIP data structure */
8515  SCIP_CONS* cons, /**< constraint to be checked */
8516  int* startindices, /**< permutation with rspect to the start times */
8517  int curtime, /**< current point in time */
8518  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8519  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8520  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8521  )
8522 {
8523  SCIP_CONSDATA* consdata;
8524  SCIP_VAR** binvars;
8525  int* coefs;
8526  int nbinvars;
8527  char name[SCIP_MAXSTRLEN];
8528  int capacity;
8529  int b;
8530 
8531  assert(nstarted > nfinished);
8532 
8533  consdata = SCIPconsGetData(cons);
8534  assert(consdata != NULL);
8535  assert(consdata->nvars > 0);
8536 
8537  capacity = consdata->capacity;
8538  assert(capacity > 0);
8539 
8540  nbinvars = 0;
8541  SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8542 
8543  /* construct row name */
8544  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8545 
8546  if( cutsasconss )
8547  {
8548  SCIP_CONS* lincons;
8549 
8550  /* create knapsack constraint for the given time point */
8551  SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8552  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) );
8553 
8554  for( b = 0; b < nbinvars; ++b )
8555  {
8556  SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8557  }
8558 
8559  /* add and release the new constraint */
8560  SCIP_CALL( SCIPaddCons(scip, lincons) );
8561  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8562  }
8563  else
8564  {
8565  SCIP_ROW* row;
8566 
8567  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8568  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8569 
8570  for( b = 0; b < nbinvars; ++b )
8571  {
8572  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8573  }
8574 
8575  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8576  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8577 
8578  if( consdata->demandrowssize == 0 )
8579  {
8580  consdata->demandrowssize = 10;
8581  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8582  }
8583  if( consdata->ndemandrows == consdata->demandrowssize )
8584  {
8585  consdata->demandrowssize *= 2;
8586  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8587  }
8588 
8589  consdata->demandrows[consdata->ndemandrows] = row;
8590  consdata->ndemandrows++;
8591  }
8592 
8593  SCIPfreeBufferArrayNull(scip, &binvars);
8594  SCIPfreeBufferArrayNull(scip, &coefs);
8595 
8596  return SCIP_OKAY;
8597 }
8598 
8599 /** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8600  * row
8601  */
8602 static
8604  SCIP* scip, /**< SCIP data structure */
8605  SCIP_CONS* cons, /**< constraint to be checked */
8606  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8607  )
8608 {
8609  SCIP_CONSDATA* consdata;
8610 
8611  int* starttimes; /* stores when each job is starting */
8612  int* endtimes; /* stores when each job ends */
8613  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8614  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8615 
8616  int nvars; /* number of activities for this constraint */
8617  int freecapacity; /* remaining capacity */
8618  int curtime; /* point in time which we are just checking */
8619  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8620 
8621  int hmin;
8622  int hmax;
8623 
8624  int j;
8625 
8626  assert(scip != NULL);
8627  assert(cons != NULL);
8628 
8629  consdata = SCIPconsGetData(cons);
8630  assert(consdata != NULL);
8631 
8632  nvars = consdata->nvars;
8633 
8634  /* if no activities are associated with this cumulative then this constraint is redundant */
8635  if( nvars == 0 )
8636  return SCIP_OKAY;
8637 
8638  assert(consdata->vars != NULL);
8639 
8640  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8641  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8642  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8643  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8644 
8645  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8646  SCIPconsGetName(cons), nvars);
8647 
8648  /* create event point arrays */
8649  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8650  starttimes, endtimes, startindices, endindices, FALSE);
8651 
8652  endindex = 0;
8653  freecapacity = consdata->capacity;
8654  hmin = consdata->hmin;
8655  hmax = consdata->hmax;
8656 
8657  /* check each startpoint of a job whether the capacity is kept or not */
8658  for( j = 0; j < nvars; ++j )
8659  {
8660  curtime = starttimes[j];
8661  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8662 
8663  if( curtime >= hmax )
8664  break;
8665 
8666  /* remove the capacity requirments for all job which start at the curtime */
8667  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8668 
8669  /* add the capacity requirments for all job which end at the curtime */
8670  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8671 
8672  assert(freecapacity <= consdata->capacity);
8673  assert(endindex <= nvars);
8674 
8675  /* endindex - points to the next job which will finish */
8676  /* j - points to the last job that has been released */
8677 
8678  /* if free capacity is smaller than zero, then add rows to the LP */
8679  if( freecapacity < 0 && curtime >= hmin )
8680  {
8681  int nextstarttime;
8682  int t;
8683 
8684  /* step forward until next job is released and see whether capacity constraint is met or not */
8685  if( j < nvars-1 )
8686  nextstarttime = starttimes[j+1];
8687  else
8688  nextstarttime = endtimes[nvars-1];
8689 
8690  nextstarttime = MIN(nextstarttime, hmax);
8691 
8692  /* create capacity restriction row for current event point */
8693  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8694 
8695  /* create for all points in time between the current event point and next start event point a row if the free
8696  * capacity is still smaller than zero */
8697  for( t = curtime+1 ; t < nextstarttime; ++t )
8698  {
8699  /* add the capacity requirments for all job which end at the curtime */
8700  addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8701 
8702  if( freecapacity < 0 )
8703  {
8704  /* add constraint */
8705  SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8706 
8707  /* create capacity restriction row */
8708  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8709  }
8710  else
8711  break;
8712  }
8713  }
8714  } /*lint --e{850}*/
8715 
8716  /* free all buffer arrays */
8717  SCIPfreeBufferArray(scip, &endindices);
8718  SCIPfreeBufferArray(scip, &startindices);
8719  SCIPfreeBufferArray(scip, &endtimes);
8720  SCIPfreeBufferArray(scip, &starttimes);
8721 
8722  return SCIP_OKAY;
8723 }
8724 
8725 /** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8726  * capacity is larger than the capacity of the cumulative constraint
8727  * - for each necessary point in time:
8728  *
8729  * sum_j sum_t demand_j * x_{j,t} <= capacity
8730  *
8731  * where x(j,t) is the binary variables of job j at time t
8732  */
8733 static
8735  SCIP* scip, /**< SCIP data structure */
8736  SCIP_CONS* cons, /**< cumulative constraint */
8737  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8738  )
8739 {
8740  SCIP_CONSDATA* consdata;
8741 
8742  consdata = SCIPconsGetData(cons);
8743  assert(consdata != NULL);
8744  assert(consdata->demandrows == NULL);
8745  assert(consdata->ndemandrows == 0);
8746 
8747  /* collect the linking constraints */
8748  if( consdata->linkingconss == NULL )
8749  {
8750  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8751  }
8752 
8753  SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8754 
8755  /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8756  if( cutsasconss )
8757  {
8758  if( SCIPconsIsInitial(cons) )
8759  {
8760  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
8761  }
8762  if( SCIPconsIsSeparated(cons) )
8763  {
8764  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
8765  }
8766  if( SCIPconsIsEnforced(cons) )
8767  {
8768  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
8769  }
8770  }
8771 
8772  return SCIP_OKAY;
8773 }
8774 
8775 /** adds linear relaxation of cumulative constraint to the LP */
8776 static
8778  SCIP* scip, /**< SCIP data structure */
8779  SCIP_CONS* cons, /**< cumulative constraint */
8780  SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
8781  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
8782  )
8783 {
8784  SCIP_CONSDATA* consdata;
8785  int r;
8786 
8787  consdata = SCIPconsGetData(cons);
8788  assert(consdata != NULL);
8789 
8790  if( consdata->demandrows == NULL )
8791  {
8792  assert(consdata->ndemandrows == 0);
8793 
8794  SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8795 
8796  return SCIP_OKAY;
8797  }
8798 
8799  for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8800  {
8801  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8802  {
8803  assert(consdata->demandrows[r] != NULL);
8804  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
8805  }
8806  }
8807 
8808  return SCIP_OKAY;
8809 }
8810 
8811 /** checks constraint for violation, and adds it as a cut if possible */
8812 static
8814  SCIP* scip, /**< SCIP data structure */
8815  SCIP_CONS* cons, /**< cumulative constraint to be separated */
8816  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8817  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8818  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8819  )
8820 { /*lint --e{715}*/
8821  SCIP_CONSDATA* consdata;
8822  int ncuts;
8823  int r;
8824 
8825  assert(scip != NULL);
8826  assert(cons != NULL);
8827  assert(separated != NULL);
8828  assert(cutoff != NULL);
8829 
8830  *separated = FALSE;
8831  *cutoff = FALSE;
8832 
8833  consdata = SCIPconsGetData(cons);
8834  assert(consdata != NULL);
8835 
8836  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8837 
8838  if( consdata->demandrows == NULL )
8839  {
8840  assert(consdata->ndemandrows == 0);
8841 
8842  SCIP_CALL( createRelaxation(scip, cons, FALSE) );
8843 
8844  return SCIP_OKAY;
8845  }
8846 
8847  ncuts = 0;
8848 
8849  /* check each row that is not contained in LP */
8850  for( r = 0; r < consdata->ndemandrows; ++r )
8851  {
8852  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8853  {
8854  SCIP_Real feasibility;
8855 
8856  if( sol != NULL )
8857  feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8858  else
8859  feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8860 
8861  if( SCIPisFeasNegative(scip, feasibility) )
8862  {
8863  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
8864  if ( *cutoff )
8865  {
8866  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8867  return SCIP_OKAY;
8868  }
8869  *separated = TRUE;
8870  ncuts++;
8871  }
8872  }
8873  }
8874 
8875  if( ncuts > 0 )
8876  {
8877  SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8878 
8879  /* if successful, reset age of constraint */
8880  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8881  (*separated) = TRUE;
8882  }
8883 
8884  return SCIP_OKAY;
8885 }
8886 
8887 /** checks constraint for violation, and adds it as a cut if possible */
8888 static
8890  SCIP* scip, /**< SCIP data structure */
8891  SCIP_CONS* cons, /**< logic or constraint to be separated */
8892  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8893  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8894  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8895  )
8896 {
8897  SCIP_CONSDATA* consdata;
8898  SCIP_ROW* row;
8899  SCIP_Real minfeasibility;
8900  int r;
8901 
8902  assert(scip != NULL);
8903  assert(cons != NULL);
8904  assert(separated != NULL);
8905  assert(cutoff != NULL);
8906 
8907  *separated = FALSE;
8908  *cutoff = FALSE;
8909 
8910  consdata = SCIPconsGetData(cons);
8911  assert(consdata != NULL);
8912 
8913  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8914 
8915  /* collect the linking constraints */
8916  if( consdata->linkingconss == NULL )
8917  {
8918  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8919  }
8920 
8921  if( !consdata->covercuts )
8922  {
8923  SCIP_CALL( createCoverCuts(scip, cons) );
8924  }
8925 
8926  row = NULL;
8927  minfeasibility = SCIPinfinity(scip);
8928 
8929  /* check each row of small covers that is not contained in LP */
8930  for( r = 0; r < consdata->nscoverrows; ++r )
8931  {
8932  if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8933  {
8934  SCIP_Real feasibility;
8935 
8936  assert(consdata->scoverrows[r] != NULL);
8937  if( sol != NULL )
8938  feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8939  else
8940  feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8941 
8942  if( minfeasibility > feasibility )
8943  {
8944  minfeasibility = feasibility;
8945  row = consdata->scoverrows[r];
8946  }
8947  }
8948  }
8949 
8950  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8951 
8952  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8953  {
8954  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8955  SCIPconsGetName(cons), minfeasibility);
8956 
8957  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8958  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8959  if ( *cutoff )
8960  return SCIP_OKAY;
8961  (*separated) = TRUE;
8962  }
8963 
8964  minfeasibility = SCIPinfinity(scip);
8965  row = NULL;
8966 
8967  /* check each row of small covers that is not contained in LP */
8968  for( r = 0; r < consdata->nbcoverrows; ++r )
8969  {
8970  if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8971  {
8972  SCIP_Real feasibility;
8973 
8974  assert(consdata->bcoverrows[r] != NULL);
8975  if( sol != NULL )
8976  feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8977  else
8978  feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8979 
8980  if( minfeasibility > feasibility )
8981  {
8982  minfeasibility = feasibility;
8983  row = consdata->bcoverrows[r];
8984  }
8985  }
8986  }
8987 
8988  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8989 
8990  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8991  {
8992  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8993  SCIPconsGetName(cons), minfeasibility);
8994 
8995  assert(row != NULL);
8996  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8997  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8998  if ( *cutoff )
8999  return SCIP_OKAY;
9000  (*separated) = TRUE;
9001  }
9002 
9003  return SCIP_OKAY;
9004 }
9005 
9006 /** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
9007 static
9009  SCIP* scip, /**< SCIP data structure */
9010  SCIP_CONS* cons, /**< constraint to be checked */
9011  int* startindices, /**< permutation with rspect to the start times */
9012  int curtime, /**< current point in time */
9013  int nstarted, /**< number of jobs that start before the curtime or at curtime */
9014  int nfinished, /**< number of jobs that finished before curtime or at curtime */
9015  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
9016  SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9017  )
9018 {
9019  SCIP_CONSDATA* consdata;
9020  char name[SCIP_MAXSTRLEN];
9021  int lhs; /* left hand side of constraint */
9022 
9023  SCIP_VAR** activevars;
9024  SCIP_ROW* row;
9025 
9026  int v;
9027 
9028  assert(nstarted > nfinished);
9029 
9030  consdata = SCIPconsGetData(cons);
9031  assert(consdata != NULL);
9032  assert(consdata->nvars > 0);
9033 
9034  SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
9035 
9036  SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
9037 
9038  if( lower )
9039  {
9040  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
9041 
9042  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, (SCIP_Real) lhs, SCIPinfinity(scip),
9043  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9044  }
9045  else
9046  {
9047  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
9048  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) lhs,
9049  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9050  }
9051 
9052  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
9053 
9054  for( v = 0; v < nstarted - nfinished; ++v )
9055  {
9056  SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
9057  }
9058 
9059  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
9060  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
9061 
9062  SCIP_CALL( SCIPaddRow(scip, row, TRUE, cutoff) );
9063 
9064  SCIP_CALL( SCIPreleaseRow(scip, &row) );
9065 
9066  /* free buffers */
9067  SCIPfreeBufferArrayNull(scip, &activevars);
9068 
9069  return SCIP_OKAY;
9070 }
9071 
9072 /** checks constraint for violation, and adds it as a cut if possible */
9073 static
9075  SCIP* scip, /**< SCIP data structure */
9076  SCIP_CONS* cons, /**< cumulative constraint to be separated */
9077  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
9078  SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
9079  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
9080  SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9081  )
9082 {
9083  SCIP_CONSDATA* consdata;
9084 
9085  int* starttimes; /* stores when each job is starting */
9086  int* endtimes; /* stores when each job ends */
9087  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
9088  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
9089 
9090  int nvars; /* number of activities for this constraint */
9091  int freecapacity; /* remaining capacity */
9092  int curtime; /* point in time which we are just checking */
9093  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
9094 
9095  int hmin;
9096  int hmax;
9097  int j;
9098 
9099  assert(scip != NULL);
9100  assert(cons != NULL);
9101 
9102  consdata = SCIPconsGetData(cons);
9103  assert(consdata != NULL);
9104 
9105  nvars = consdata->nvars;
9106 
9107  /* if no activities are associated with this cumulative then this constraint is redundant */
9108  if( nvars <= 1 )
9109  return SCIP_OKAY;
9110 
9111  assert(consdata->vars != NULL);
9112 
9113  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
9114  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
9115  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9116  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9117 
9118  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9119  SCIPconsGetName(cons), nvars);
9120 
9121  /* create event point arrays */
9122  createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9123 
9124  /* now nvars might be smaller than before! */
9125 
9126  endindex = 0;
9127  freecapacity = consdata->capacity;
9128  hmin = consdata->hmin;
9129  hmax = consdata->hmax;
9130 
9131  /* check each startpoint of a job whether the capacity is kept or not */
9132  for( j = 0; j < nvars && !(*cutoff); ++j )
9133  {
9134  curtime = starttimes[j];
9135 
9136  if( curtime >= hmax )
9137  break;
9138 
9139  /* remove the capacity requirements for all job which start at the curtime */
9140  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9141 
9142  /* add the capacity requirments for all job which end at the curtime */
9143  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9144 
9145  assert(freecapacity <= consdata->capacity);
9146  assert(endindex <= nvars);
9147 
9148  /* endindex - points to the next job which will finish */
9149  /* j - points to the last job that has been released */
9150 
9151  /* if free capacity is smaller than zero, then add rows to the LP */
9152  if( freecapacity < 0 && curtime >= hmin)
9153  {
9154  /* create capacity restriction row for current event point */
9155  SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower, cutoff) );
9156  *separated = TRUE;
9157  }
9158  } /*lint --e{850}*/
9159 
9160  /* free all buffer arrays */
9161  SCIPfreeBufferArray(scip, &endindices);
9162  SCIPfreeBufferArray(scip, &startindices);
9163  SCIPfreeBufferArray(scip, &endtimes);
9164  SCIPfreeBufferArray(scip, &starttimes);
9165 
9166  return SCIP_OKAY;
9167 }
9168 
9169 /**@} */
9170 
9171 
9172 /**@name Presolving
9173  *
9174  * @{
9175  */
9176 
9177 #ifndef NDEBUG
9178 /** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9179  * correct
9180  */
9181 static
9183  SCIP* scip, /**< SCIP data structure */
9184  SCIP_CONS* cons /**< constraint to be checked */
9185  )
9186 {
9187  SCIP_CONSDATA* consdata;
9188  int capacity;
9189  int nvars;
9190  int j;
9191 
9192  assert(scip != NULL);
9193  assert(cons != NULL);
9194 
9195  consdata = SCIPconsGetData(cons);
9196  assert(consdata != NULL);
9197 
9198  nvars = consdata->nvars;
9199 
9200  /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9201  if( nvars <= 1 )
9202  return TRUE;
9203 
9204  assert(consdata->vars != NULL);
9205  capacity = consdata->capacity;
9206 
9207  /* check each activity: if demand is larger than capacity the problem is infeasible */
9208  for ( j = 0; j < nvars; ++j )
9209  {
9210  if( consdata->demands[j] > capacity )
9211  return FALSE;
9212  }
9213 
9214  return TRUE;
9215 }
9216 #endif
9217 
9218 /** delete constraint if it consists of at most one job
9219  *
9220  * @todo this method needs to be adjusted w.r.t. effective horizon
9221  */
9222 static
9224  SCIP* scip, /**< SCIP data structure */
9225  SCIP_CONS* cons, /**< constraint to propagate */
9226  int* ndelconss, /**< pointer to store the number of deleted constraints */
9227  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9228  )
9229 {
9230  SCIP_CONSDATA* consdata;
9231 
9232  assert(scip != NULL);
9233  assert(cons != NULL);
9234 
9235  consdata = SCIPconsGetData(cons);
9236  assert(consdata != NULL);
9237 
9238  if( consdata->nvars == 0 )
9239  {
9240  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9241 
9242  SCIP_CALL( SCIPdelCons(scip, cons) );
9243  (*ndelconss)++;
9244  }
9245  else if( consdata->nvars == 1 )
9246  {
9247  if( consdata->demands[0] > consdata->capacity )
9248  (*cutoff) = TRUE;
9249  else
9250  {
9251  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9252 
9253  SCIP_CALL( SCIPdelCons(scip, cons) );
9254  (*ndelconss)++;
9255  }
9256  }
9257 
9258  return SCIP_OKAY;
9259 }
9260 
9261 /** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9262  * this is done in the SCIP_DECL_CONSINITPRE() callback
9263  */
9264 static
9266  SCIP* scip, /**< SCIP data structure */
9267  SCIP_CONS* cons /**< constraint to propagate */
9268  )
9269 {
9270  SCIP_CONSDATA* consdata;
9271  SCIP_VAR* var;
9272  int demand;
9273  int duration;
9274  int hmin;
9275  int hmax;
9276  int est;
9277  int lct;
9278  int j;
9279 
9280  assert(scip != NULL);
9281  assert(cons != NULL);
9282 
9283  consdata = SCIPconsGetData(cons);
9284  assert(consdata != NULL);
9285 
9286  hmin = consdata->hmin;
9287  hmax = consdata->hmax;
9288 
9289  SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9290  SCIPconsGetName(cons), hmin, hmax);
9291 
9292  for( j = consdata->nvars-1; j >= 0; --j )
9293  {
9294  var = consdata->vars[j];
9295  demand = consdata->demands[j];
9296  duration = consdata->durations[j];
9297 
9298  /* earliest completion time (ect) and latest start time (lst) */
9299  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9300  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9301 
9302  if( demand == 0 || duration == 0 )
9303  {
9304  /* jobs with zero demand or zero duration can be removed */
9305  SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
9306  SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9307 
9308  /* remove variable form constraint */
9309  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9310  }
9311  else if( est >= hmax || lct <= hmin )
9312  {
9313  SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
9314  SCIPvarGetName(var), est, lct - duration, duration);
9315 
9316  /* delete variable at the given position */
9317  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9318 
9319  /* for the statistic we count the number of jobs which are irrelevant */
9320  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9321  }
9322  }
9323 
9324  return SCIP_OKAY;
9325 }
9326 
9327 /** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9328 static
9330  SCIP* scip, /**< SCIP data structure */
9331  SCIP_CONSDATA* consdata, /**< constraint data */
9332  int pos, /**< position of job in the consdata */
9333  int* nchgbds, /**< pointer to store the number of changed bounds */
9334  int* naddconss, /**< pointer to store the number of added constraints */
9335  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9336  )
9337 {
9338  SCIP_VAR* var;
9339  SCIP_Bool tightened;
9340  int duration;
9341  int ect;
9342  int lst;
9343 
9344  assert(scip != NULL);
9345 
9346  /* zero energy jobs should be removed already */
9347  assert(consdata->durations[pos] > 0);
9348  assert(consdata->demands[pos] > 0);
9349 
9350  var = consdata->vars[pos];
9351  assert(var != NULL);
9352  duration = consdata->durations[pos];
9353 
9354  /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9355  SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9356  SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9357 
9358  /* earliest completion time (ect) and latest start time (lst) */
9359  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9360  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9361 
9362  /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9363  if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9364  return SCIP_OKAY;
9365 
9366  if( ect > consdata->hmin && lst < consdata->hmax )
9367  {
9368  /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9369  *cutoff = TRUE;
9370  }
9371  else if( lst < consdata->hmax )
9372  {
9373  /* move the latest start time of this job in such a way that it finishes before or at hmin */
9374  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9375  assert(tightened);
9376  assert(!(*cutoff));
9377  (*nchgbds)++;
9378  }
9379  else if( ect > consdata->hmin )
9380  {
9381  /* move the earliest start time of this job in such a way that it starts after or at hmax */
9382  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9383  assert(tightened);
9384  assert(!(*cutoff));
9385  (*nchgbds)++;
9386  }
9387  else
9388  {
9389  /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9390  * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9391  *
9392  * (var <= hmin - duration) /\ (var >= hmax)
9393  */
9394  SCIP_CONS* cons;
9395 
9396  SCIP_VAR* vartuple[2];
9397  SCIP_BOUNDTYPE boundtypetuple[2];
9398  SCIP_Real boundtuple[2];
9399 
9400  char name[SCIP_MAXSTRLEN];
9401  int leftbound;
9402  int rightbound;
9403 
9404  leftbound = consdata->hmin - duration;
9405  rightbound = consdata->hmax;
9406 
9407  /* allocate temporary memory for arrays */
9408  vartuple[0] = var;
9409  vartuple[1] = var;
9410  boundtuple[0] = (SCIP_Real)leftbound;
9411  boundtuple[1] = (SCIP_Real)rightbound;
9412  boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9413  boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9414 
9415  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9416  SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9417 
9418  /* create and add bounddisjunction constraint */
9419  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9420  TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9421 
9422  SCIPdebugPrintCons(scip, cons, NULL);
9423 
9424  /* add and release the new constraint */
9425  SCIP_CALL( SCIPaddCons(scip, cons) );
9426  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9427  (*naddconss)++;
9428  }
9429 
9430  return SCIP_OKAY;
9431 }
9432 
9433 /** try to removed over sizeed jobs (the demand is larger than the capacity) */
9434 static
9436  SCIP* scip, /**< SCIP data structure */
9437  SCIP_CONS* cons, /**< constraint */
9438  int* nchgbds, /**< pointer to store the number of changed bounds */
9439  int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9440  int* naddconss, /**< pointer to store the number of added constraints */
9441  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9442  )
9443 {
9444  SCIP_CONSDATA* consdata;
9445  int capacity;
9446  int j;
9447 
9448  consdata = SCIPconsGetData(cons);
9449  assert(consdata != NULL);
9450 
9451  /* if a cutoff was already detected just return */
9452  if( *cutoff )
9453  return SCIP_OKAY;
9454 
9455  capacity = consdata->capacity;
9456 
9457  for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9458  {
9459  if( consdata->demands[j] > capacity )
9460  {
9461  SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9462 
9463  /* remove variable form constraint */
9464  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9465  (*nchgcoefs)++;
9466  }
9467  }
9468 
9469  SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9470 
9471  return SCIP_OKAY;
9472 }
9473 
9474 /** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9475 static
9477  SCIP* scip, /**< SCIP data structure */
9478  SCIP_VAR* var, /**< integer variable to fix */
9479  SCIP_Bool uplock, /**< has thet start time variable a up lock */
9480  int* nfixedvars /**< pointer to store the number fixed variables */
9481  )
9482 {
9483  SCIP_Bool infeasible;
9484  SCIP_Bool tightened;
9485  SCIP_Bool roundable;
9486 
9487  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9488  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9489  */
9490  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9491  return SCIP_OKAY;
9492 
9493  /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9494  * handler is the only one locking that variable up
9495  */
9496  assert(uplock == TRUE || uplock == FALSE);
9497  assert((int)TRUE == 1); /*lint !e506*/
9498  assert((int)FALSE == 0); /*lint !e506*/
9499 
9500  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)(uplock) )
9501  return SCIP_OKAY;
9502 
9503  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9504 
9505  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9506  * (the transformed problem is always a minimization problem)
9507  */
9508  if( !roundable )
9509  return SCIP_OKAY;
9510 
9511  SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9513 
9514  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9515  assert(!infeasible);
9516 
9517  if( tightened )
9518  {
9519  SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9520  (*nfixedvars)++;
9521  }
9522 
9523  return SCIP_OKAY;
9524 }
9525 
9526 /** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9527 static
9529  SCIP* scip, /**< SCIP data structure */
9530  SCIP_VAR* var, /**< integer variable to fix */
9531  SCIP_Bool downlock, /**< has the variable a down lock */
9532  int* nfixedvars /**< pointer to store the number fixed variables */
9533  )
9534 {
9535  SCIP_Bool infeasible;
9536  SCIP_Bool tightened;
9537  SCIP_Bool roundable;
9538 
9539  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9540  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9541  */
9542  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9543  return SCIP_OKAY;
9544 
9545  /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9546  * handler is the only one locking that variable down
9547  */
9548  assert(downlock == TRUE || downlock == FALSE);
9549  assert((int)TRUE == 1); /*lint !e506*/
9550  assert((int)FALSE == 0); /*lint !e506*/
9551 
9552  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)(downlock) )
9553  return SCIP_OKAY;
9554 
9555  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9556 
9557  /* is it possible, to round variable down w.r.t. objective function? */
9558  if( !roundable )
9559  return SCIP_OKAY;
9560 
9561  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9562  assert(!infeasible);
9563 
9564  if( tightened )
9565  {
9566  SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9567  (*nfixedvars)++;
9568  }
9569 
9570  return SCIP_OKAY;
9571 }
9572 
9573 /** normalize cumulative condition */
9574 static
9576  SCIP* scip, /**< SCIP data structure */
9577  int nvars, /**< number of start time variables (activities) */
9578  int* demands, /**< array of demands */
9579  int* capacity, /**< pointer to store the changed cumulative capacity */
9580  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9581  int* nchgsides /**< pointer to count number of side changes */
9582  )
9583 { /*lint --e{715}*/
9584  SCIP_Longint gcd;
9585  int mindemand1;
9586  int mindemand2;
9587  int v;
9588 
9589  if( *capacity == 1 || nvars <= 1 )
9590  return;
9591 
9592  assert(demands[nvars-1] <= *capacity);
9593  assert(demands[nvars-2] <= *capacity);
9594 
9595  gcd = (SCIP_Longint)demands[nvars-1];
9596  mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9597  mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9598 
9599  for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9600  {
9601  assert(mindemand1 <= mindemand2);
9602  assert(demands[v] <= *capacity);
9603 
9604  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9605 
9606  if( mindemand1 > demands[v] )
9607  {
9608  mindemand2 = mindemand1;
9609  mindemand1 = demands[v];
9610  }
9611  else if( mindemand2 > demands[v] )
9612  mindemand2 = demands[v];
9613  }
9614 
9615  if( mindemand1 + mindemand2 > *capacity )
9616  {
9617  SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9618 
9619  for( v = 0; v < nvars; ++v )
9620  demands[v] = 1;
9621 
9622  (*capacity) = 1;
9623 
9624  (*nchgcoefs) += nvars;
9625  (*nchgsides)++;
9626  }
9627  else if( gcd >= 2 )
9628  {
9629  SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9630 
9631  for( v = 0; v < nvars; ++v )
9632  demands[v] /= (int) gcd;
9633 
9634  (*capacity) /= (int) gcd;
9635 
9636  (*nchgcoefs) += nvars;
9637  (*nchgsides)++;
9638  }
9639 }
9640 
9641 /** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9642  * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9643  * capacity since in that case none of the jobs can run in parallel
9644  */
9645 static
9646 void normalizeDemands(
9647  SCIP* scip, /**< SCIP data structure */
9648  SCIP_CONS* cons, /**< cumulative constraint */
9649  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9650  int* nchgsides /**< pointer to count number of side changes */
9651  )
9652 {
9653  SCIP_CONSDATA* consdata;
9654  int capacity;
9655 
9656  assert(nchgcoefs != NULL);
9657  assert(nchgsides != NULL);
9658  assert(!SCIPconsIsModifiable(cons));
9659 
9660  consdata = SCIPconsGetData(cons);
9661  assert(consdata != NULL);
9662 
9663  if( consdata->normalized )
9664  return;
9665 
9666  capacity = consdata->capacity;
9667 
9668  /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9669 
9670  normalizeCumulativeCondition(scip, consdata->nvars, consdata->demands, &consdata->capacity, nchgcoefs, nchgsides);
9671 
9672  consdata->normalized = TRUE;
9673 
9674  if( capacity > consdata->capacity )
9675  consdata->varbounds = FALSE;
9676 }
9677 
9678 /** computes for the given cumulative condition the effective horizon */
9679 static
9681  SCIP* scip, /**< SCIP data structure */
9682  int nvars, /**< number of variables (jobs) */
9683  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9684  int* durations, /**< array containing corresponding durations */
9685  int* demands, /**< array containing corresponding demands */
9686  int capacity, /**< available cumulative capacity */
9687  int* hmin, /**< pointer to store the left bound of the effective horizon */
9688  int* hmax, /**< pointer to store the right bound of the effective horizon */
9689  int* split /**< point were the cumulative condition can be split */
9690  )
9691 {
9692  SCIP_PROFILE* profile;
9693 
9694  /* create empty resource profile with infinity resource capacity */
9695  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9696 
9697  /* create worst case resource profile */
9698  SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
9699 
9700  /* print resource profile in if SCIP_DEBUG is defined */
9701  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
9702 
9703  /* computes the first time point where the resource capacity can be violated */
9704  (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9705 
9706  /* computes the first time point where the resource capacity is satisfied for sure */
9707  (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9708 
9709  (*split) = (*hmax);
9710 
9711  if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9712  {
9713  int* timepoints;
9714  int* loads;
9715  int ntimepoints;
9716  int t;
9717 
9718  /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9719  * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9720  * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9721  * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9722  * explain the certain "old" bound changes
9723  */
9724 
9725  /* search for time points */
9726  ntimepoints = SCIPprofileGetNTimepoints(profile);
9727  timepoints = SCIPprofileGetTimepoints(profile);
9728  loads = SCIPprofileGetLoads(profile);
9729 
9730  /* 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 */
9731  for( t = 0; t < ntimepoints; ++t )
9732  {
9733  /* ignore all time points before the effective horizon */
9734  if( timepoints[t] <= *hmin )
9735  continue;
9736 
9737  /* ignore all time points after the effective horizon */
9738  if( timepoints[t] >= *hmax )
9739  break;
9740 
9741  /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9742  * can split the cumulative constraint into two cumulative constraints
9743  */
9744  if( loads[t] <= capacity )
9745  {
9746  (*split) = timepoints[t];
9747  break;
9748  }
9749  }
9750  }
9751 
9752  /* free worst case profile */
9753  SCIPprofileFree(&profile);
9754 
9755  return SCIP_OKAY;
9756 }
9757 
9758 /** creates and adds a cumulative constraint */
9759 static
9761  SCIP* scip, /**< SCIP data structure */
9762  const char* name, /**< name of constraint */
9763  int nvars, /**< number of variables (jobs) */
9764  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9765  int* durations, /**< array containing corresponding durations */
9766  int* demands, /**< array containing corresponding demands */
9767  int capacity, /**< available cumulative capacity */
9768  int hmin, /**< left bound of time axis to be considered (including hmin) */
9769  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9770  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9771  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9772  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9773  * Usually set to TRUE. */
9774  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9775  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9776  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9777  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9778  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9779  * Usually set to TRUE. */
9780  SCIP_Bool local, /**< is constraint only valid locally?
9781  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9782  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9783  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9784  * adds coefficients to this constraint. */
9785  SCIP_Bool dynamic, /**< is constraint subject to aging?
9786  * Usually set to FALSE. Set to TRUE for own cuts which
9787  * are seperated as constraints. */
9788  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9789  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9790  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9791  * if it may be moved to a more global node?
9792  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9793  )
9794 {
9795  SCIP_CONS* cons;
9796 
9797  /* creates cumulative constraint and adds it to problem */
9798  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9799  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9800 
9801  /* adjust the effective time horizon of the new constraint */
9802  SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9803  SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9804 
9805  /* add and release new cumulative constraint */
9806  SCIP_CALL( SCIPaddCons(scip, cons) );
9807  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9808 
9809  return SCIP_OKAY;
9810 }
9811 
9812 /** computes the effective horizon and checks if the constraint can be decompsed */
9813 static
9815  SCIP* scip, /**< SCIP data structure */
9816  SCIP_CONS* cons, /**< cumulative constraint */
9817  int* ndelconss, /**< pointer to store the number of deleted constraints */
9818  int* naddconss, /**< pointer to store the number of added constraints */
9819  int* nchgsides /**< pointer to store the number of changed sides */
9820  )
9821 {
9822  SCIP_CONSDATA* consdata;
9823  int hmin;
9824  int hmax;
9825  int split;
9826 
9827  consdata = SCIPconsGetData(cons);
9828  assert(consdata != NULL);
9829 
9830  if( consdata->nvars <= 1 )
9831  return SCIP_OKAY;
9832 
9833  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9834  consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9835 
9836  /* check if this time point improves the effective horizon */
9837  if( consdata->hmin < hmin )
9838  {
9839  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9840 
9841  consdata->hmin = hmin;
9842  (*nchgsides)++;
9843  }
9844 
9845  /* check if this time point improves the effective horizon */
9846  if( consdata->hmax > hmax )
9847  {
9848  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9849  consdata->hmax = hmax;
9850  (*nchgsides)++;
9851  }
9852 
9853  /* check if the constraint is redundant */
9854  if( consdata->hmax <= consdata->hmin )
9855  {
9856  SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9857  SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9858 
9859  SCIP_CALL( SCIPdelCons(scip, cons) );
9860  (*ndelconss)++;
9861  }
9862  else if( consdata->hmin < split && split < consdata->hmax )
9863  {
9864  char name[SCIP_MAXSTRLEN];
9865  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9866 
9867  SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9868  SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9869 
9870  assert(split < consdata->hmax);
9871 
9872  /* creates cumulative constraint and adds it to problem */
9873  SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9874  consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9877 
9878  /* adjust the effective time horizon of the constraint */
9879  consdata->hmax = split;
9880 
9881  assert(consdata->hmin < consdata->hmax);
9882 
9883  /* for the statistic we count the number of time we decompose a cumulative constraint */
9885  (*naddconss)++;
9886  }
9887 
9888  return SCIP_OKAY;
9889 }
9890 
9891 
9892 /** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9893  *
9894  * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9895  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9896  *
9897  * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9898  * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9899  * down-lock of the corresponding start time variable can be removed.
9900  *
9901  * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9902  * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9903  * negative, than the job can be dual fixed to its earlier start time (est).
9904  *
9905  * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9906  * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9907  * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9908  *
9909  * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9910  * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9911  * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9912  * form variable domain is dual feasible.
9913  *
9914  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9915  * the cumulative condition; The deletion has to be done later.
9916  */
9917 static
9919  SCIP* scip, /**< SCIP data structure */
9920  int nvars, /**< number of start time variables (activities) */
9921  SCIP_VAR** vars, /**< array of start time variables */
9922  int* durations, /**< array of durations */
9923  int hmin, /**< left bound of time axis to be considered (including hmin) */
9924  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9925  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9926  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9927  SCIP_CONS* cons, /**< underlying constraint, or NULL */
9928  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9929  int* nfixedvars, /**< pointer to store the number of fixed variables */
9930  int* nchgsides, /**< pointer to store the number of changed sides */
9931  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9932  )
9933 {
9934  SCIP_Real* downimpllbs;
9935  SCIP_Real* downimplubs;
9936  SCIP_Real* downproplbs;
9937  SCIP_Real* downpropubs;
9938  SCIP_Real* upimpllbs;
9939  SCIP_Real* upimplubs;
9940  SCIP_Real* upproplbs;
9941  SCIP_Real* uppropubs;
9942 
9943  int firstminect;
9944  int secondminect;
9945  int v;
9946 
9947  /* get temporary memory for storing probing results needed for step (4) and (5) */
9948  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9949  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9950  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9951  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9952  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9953  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9954  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9955  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9956 
9957  assert(scip != NULL);
9958  assert(nvars > 1);
9959  assert(cons != NULL);
9960 
9961  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9962 
9963  firstminect = INT_MAX;
9964  secondminect = INT_MAX;
9965 
9966  /* compute the two smallest earlier completion times; which are needed for step (5) */
9967  for( v = 0; v < nvars; ++v )
9968  {
9969  int ect;
9970 
9971  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9972 
9973  if( ect < firstminect )
9974  {
9975  secondminect = firstminect;
9976  firstminect = ect;
9977  }
9978  else if( ect < secondminect )
9979  secondminect = ect;
9980  }
9981 
9982  /* loop over all jobs and check if one of the 5 reductions can be applied */
9983  for( v = 0; v < nvars; ++v )
9984  {
9985  SCIP_VAR* var;
9986  int duration;
9987 
9988  int alternativelb;
9989  int minect;
9990  int est;
9991  int ect;
9992  int lst;
9993  int lct;
9994 
9995  var = vars[v];
9996  assert(var != NULL);
9997 
9998  duration = durations[v];
9999  assert(duration > 0);
10000 
10001  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10002  * time (lct)
10003  */
10004  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10005  ect = est + duration;
10006  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10007  lct = lst + duration;
10008 
10009  /* compute the earliest completion time of all remaining jobs */
10010  if( ect == firstminect )
10011  minect = secondminect;
10012  else
10013  minect = firstminect;
10014 
10015  /* compute potential alternative lower bound (step (4) and (5)) */
10016  alternativelb = MAX(hmin+1, minect);
10017  alternativelb = MIN(alternativelb, hmax);
10018 
10019  if( lct <= hmin )
10020  {
10021  /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
10022  * cumulative condition
10023  */
10024  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10025  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10026 
10027  /* mark variable to be irrelevant */
10028  irrelevants[v] = TRUE;
10029 
10030  /* for the statistic we count the number of jobs which are irrelevant */
10031  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10032  }
10033  else if( lst <= hmin && SCIPconsIsChecked(cons) )
10034  {
10035  /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
10036  * so the down lock can be omitted
10037  */
10038 
10039  assert(downlocks != NULL);
10040  assert(uplocks != NULL);
10041 
10042  if( !uplocks[v] )
10043  {
10044  /* the variables has no up lock and we can also remove the down lock;
10045  * => lst <= hmin and ect >= hmax
10046  * => remove job and reduce capacity by the demand of that job
10047  *
10048  * We mark the job to be deletable. The removement together with the capacity reducion is done later
10049  */
10050 
10051  SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
10052  SCIPvarGetName(var), ect - duration, lst, duration);
10053 
10054  /* mark variable to be irrelevant */
10055  irrelevants[v] = TRUE;
10056 
10057  /* for the statistic we count the number of jobs which always run during the effective horizon */
10059  }
10060 
10061  if( downlocks[v] )
10062  {
10063  SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
10064  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10065 
10066  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
10067  downlocks[v] = FALSE;
10068  (*nchgsides)++;
10069 
10070  /* for the statistic we count the number of removed locks */
10072  }
10073  }
10074  else if( ect <= hmin )
10075  {
10076  /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
10077  * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
10078  * removed form the cumulative condition after it was fixed to its earliest start time
10079  */
10080 
10081  /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
10082  * bound;
10083  */
10084  if( downlocks != NULL && SCIPconsIsChecked(cons) )
10085  {
10086  /* fix integer start time variable if possible to it lower bound */
10087  SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
10088  }
10089 
10090  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10091  {
10092  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
10093  SCIPvarGetName(var), ect - duration, lst, duration);
10094 
10095  /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
10096  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
10097 
10098  /* mark variable to be irrelevant */
10099  irrelevants[v] = TRUE;
10100 
10101  /* for the statistic we count the number of jobs which are dual fixed */
10103  }
10104  }
10105  else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10106  {
10107  assert(downlocks != NULL);
10108 
10109  /* check step (4) and (5) */
10110 
10111  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10112  * is in favor of rounding the variable down
10113  */
10114  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
10115  {
10116  SCIP_Bool roundable;
10117 
10118  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10119 
10120  if( roundable )
10121  {
10122  if( alternativelb > lst )
10123  {
10124  SCIP_Bool infeasible;
10125  SCIP_Bool fixed;
10126 
10127  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10128  assert(!infeasible);
10129  assert(fixed);
10130 
10131  (*nfixedvars)++;
10132 
10133  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10134  * constraints
10135  */
10137  }
10138  else
10139  {
10140  SCIP_Bool success;
10141 
10142  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10143  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10144  * infeasible we can apply the dual reduction; otherwise we do nothing
10145  */
10146  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10147  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10148  nfixedvars, &success, cutoff) );
10149 
10150  if( success )
10151  {
10153  }
10154  }
10155  }
10156  }
10157  }
10158 
10159  SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10160  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10161  }
10162 
10163  /* free temporary memory */
10164  SCIPfreeBufferArray(scip, &uppropubs);
10165  SCIPfreeBufferArray(scip, &upproplbs);
10166  SCIPfreeBufferArray(scip, &upimplubs);
10167  SCIPfreeBufferArray(scip, &upimpllbs);
10168  SCIPfreeBufferArray(scip, &downpropubs);
10169  SCIPfreeBufferArray(scip, &downproplbs);
10170  SCIPfreeBufferArray(scip, &downimplubs);
10171  SCIPfreeBufferArray(scip, &downimpllbs);
10172 
10173  return SCIP_OKAY;
10174 }
10175 
10176 /** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10177  *
10178  * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10179  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10180  *
10181  * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10182  * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10183  * up-lock of the corresponding start time variable can be removed.
10184  *
10185  * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10186  * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10187  * positive, than the job can be dual fixed to its latest start time (lst).
10188  *
10189  * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10190  * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10191  * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10192  * of the corresponding job).
10193 
10194  * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10195  * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10196  * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10197  * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10198  *
10199  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10200  * the cumulative condition; The deletion has to be done later.
10201  */
10202 static
10204  SCIP* scip, /**< SCIP data structure */
10205  int nvars, /**< number of start time variables (activities) */
10206  SCIP_VAR** vars, /**< array of start time variables */
10207  int* durations, /**< array of durations */
10208  int hmin, /**< left bound of time axis to be considered (including hmin) */
10209  int hmax, /**< right bound of time axis to be considered (not including hmax) */
10210  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10211  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10212  SCIP_CONS* cons, /**< underlying constraint, or NULL */
10213  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10214  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10215  int* nchgsides, /**< pointer to store the number of changed sides */
10216  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10217  )
10218 {
10219  SCIP_Real* downimpllbs;
10220  SCIP_Real* downimplubs;
10221  SCIP_Real* downproplbs;
10222  SCIP_Real* downpropubs;
10223  SCIP_Real* upimpllbs;
10224  SCIP_Real* upimplubs;
10225  SCIP_Real* upproplbs;
10226  SCIP_Real* uppropubs;
10227 
10228  int firstmaxlst;
10229  int secondmaxlst;
10230  int v;
10231 
10232  /* get temporary memory for storing probing results needed for step (4) and (5) */
10233  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10234  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10235  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10236  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10237  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10238  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10239  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10240  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10241 
10242  assert(scip != NULL);
10243  assert(nvars > 1);
10244  assert(cons != NULL);
10245 
10246  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10247 
10248  firstmaxlst = INT_MIN;
10249  secondmaxlst = INT_MIN;
10250 
10251  /* compute the two largest latest start times; which are needed for step (5) */
10252  for( v = 0; v < nvars; ++v )
10253  {
10254  int lst;
10255 
10256  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(vars[v]));
10257 
10258  if( lst > firstmaxlst )
10259  {
10260  secondmaxlst = firstmaxlst;
10261  firstmaxlst = lst;
10262  }
10263  else if( lst > secondmaxlst )
10264  secondmaxlst = lst;
10265  }
10266 
10267  /* loop over all jobs and check if one of the 5 reductions can be applied */
10268  for( v = 0; v < nvars; ++v )
10269  {
10270  SCIP_VAR* var;
10271  int duration;
10272 
10273  int alternativeub;
10274  int maxlst;
10275  int est;
10276  int ect;
10277  int lst;
10278 
10279  var = vars[v];
10280  assert(var != NULL);
10281 
10282  duration = durations[v];
10283  assert(duration > 0);
10284 
10285  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10286  * time (lct)
10287  */
10288  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10289  ect = est + duration;
10290  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10291 
10292  /* compute the latest start time of all remaining jobs */
10293  if( lst == firstmaxlst )
10294  maxlst = secondmaxlst;
10295  else
10296  maxlst = firstmaxlst;
10297 
10298  /* compute potential alternative upper bound (step (4) and (5)) */
10299  alternativeub = MIN(hmax - 1, maxlst) - duration;
10300  alternativeub = MAX(alternativeub, hmin);
10301 
10302  if( est >= hmax )
10303  {
10304  /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10305  * cumulative condition
10306  */
10307  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10308  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10309 
10310  /* mark variable to be irrelevant */
10311  irrelevants[v] = TRUE;
10312 
10313  /* for the statistic we count the number of jobs which are irrelevant */
10314  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10315  }
10316  else if( ect >= hmax && SCIPconsIsChecked(cons) )
10317  {
10318  assert(downlocks != NULL);
10319  assert(uplocks != NULL);
10320 
10321  /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10322  * so the up lock can be omitted
10323  */
10324 
10325  if( !downlocks[v] )
10326  {
10327  /* the variables has no down lock and we can also remove the up lock;
10328  * => lst <= hmin and ect >= hmax
10329  * => remove job and reduce capacity by the demand of that job
10330  */
10331  SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10332  SCIPvarGetName(var), est, lst, duration);
10333 
10334  /* mark variable to be irrelevant */
10335  irrelevants[v] = TRUE;
10336 
10337  /* for the statistic we count the number of jobs which always run during the effective horizon */
10339  }
10340 
10341  if( uplocks[v] )
10342  {
10343  SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10344  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10345 
10346  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10347  uplocks[v] = FALSE;
10348  (*nchgsides)++;
10349 
10350  /* for the statistic we count the number of removed locks */
10352  }
10353  }
10354  else if( lst >= hmax )
10355  {
10356  /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10357  * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10358  * removed form the cumulative condition after it was fixed to its latest start time
10359  */
10360 
10361  /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10362  * bound
10363  */
10364  if( uplocks != NULL && SCIPconsIsChecked(cons) )
10365  {
10366  /* fix integer start time variable if possible to its upper bound */
10367  SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10368  }
10369 
10370  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10371  {
10372  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10373  SCIPvarGetName(var), est, lst, duration);
10374 
10375  /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10376  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10377 
10378  /* mark variable to be irrelevant */
10379  irrelevants[v] = TRUE;
10380 
10381  /* for the statistic we count the number of jobs which are dual fixed */
10383  }
10384  }
10385  else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10386  {
10387  assert(uplocks != NULL);
10388 
10389  /* check step (4) and (5) */
10390 
10391  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10392  * is in favor of rounding the variable down
10393  */
10394  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
10395  {
10396  SCIP_Bool roundable;
10397 
10398  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10399 
10400  if( roundable )
10401  {
10402  if( alternativeub < est )
10403  {
10404  SCIP_Bool infeasible;
10405  SCIP_Bool fixed;
10406 
10407  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10408  assert(!infeasible);
10409  assert(fixed);
10410 
10411  (*nfixedvars)++;
10412 
10413  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10414  * constraints
10415  */
10417  }
10418  else
10419  {
10420  SCIP_Bool success;
10421 
10422  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10423  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10424  * in infeasible we can apply the dual reduction; otherwise we do nothing
10425  */
10426  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10427  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10428  nfixedvars, &success, cutoff) );
10429 
10430  if( success )
10431  {
10433  }
10434  }
10435  }
10436  }
10437  }
10438  }
10439 
10440  /* free temporary memory */
10441  SCIPfreeBufferArray(scip, &uppropubs);
10442  SCIPfreeBufferArray(scip, &upproplbs);
10443  SCIPfreeBufferArray(scip, &upimplubs);
10444  SCIPfreeBufferArray(scip, &upimpllbs);
10445  SCIPfreeBufferArray(scip, &downpropubs);
10446  SCIPfreeBufferArray(scip, &downproplbs);
10447  SCIPfreeBufferArray(scip, &downimplubs);
10448  SCIPfreeBufferArray(scip, &downimpllbs);
10449 
10450  return SCIP_OKAY;
10451 }
10452 
10453 /** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10454 static
10456  SCIP* scip, /**< SCIP data structure */
10457  SCIP_CONS* cons, /**< cumulative constraint */
10458  int* nfixedvars, /**< pointer to store the number of fixed variables */
10459  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10460  int* nchgsides, /**< pointer to store the number of changed sides */
10461  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10462  )
10463 {
10464  SCIP_CONSDATA* consdata;
10465  SCIP_Bool* irrelevants;
10466  int nvars;
10467  int v;
10468 
10469  assert(scip != NULL);
10470  assert(cons != NULL);
10471  assert(!(*cutoff));
10472 
10473  consdata = SCIPconsGetData(cons);
10474  assert(consdata != NULL);
10475 
10476  nvars = consdata->nvars;
10477 
10478  if( nvars <= 1 )
10479  return SCIP_OKAY;
10480 
10481  SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10482  BMSclearMemoryArray(irrelevants, nvars);
10483 
10484  /* presolve constraint form the earlier start time point of view */
10485  SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10486  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10487  irrelevants, nfixedvars, nchgsides, cutoff) );
10488 
10489  /* presolve constraint form the latest completion time point of view */
10490  SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10491  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10492  irrelevants, nfixedvars, nchgsides, cutoff) );
10493 
10494  /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10495  * order to ensure a correct behaviour
10496  */
10497  for( v = nvars-1; v >= 0; --v )
10498  {
10499  if( irrelevants[v] )
10500  {
10501  SCIP_VAR* var;
10502  int ect;
10503  int lst;
10504 
10505  var = consdata->vars[v];
10506  assert(var != NULL);
10507 
10508  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10509  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10510 
10511  /* check if the jobs runs completely during the effective horizon */
10512  if( lst <= consdata->hmin && ect >= consdata->hmax )
10513  {
10514  if( consdata->capacity < consdata->demands[v] )
10515  {
10516  *cutoff = TRUE;
10517  break;
10518  }
10519 
10520  consdata->capacity -= consdata->demands[v];
10521  consdata->varbounds = FALSE;
10522  }
10523 
10524  SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10525  (*nchgcoefs)++;
10526  }
10527  }
10528 
10529  SCIPfreeBufferArray(scip, &irrelevants);
10530 
10531  return SCIP_OKAY;
10532 }
10533 
10534 /** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10535 static
10536 void collectDemands(
10537  SCIP* scip, /**< SCIP data structure */
10538  SCIP_CONSDATA* consdata, /**< constraint data */
10539  int* startindices, /**< permutation with rspect to the start times */
10540  int curtime, /**< current point in time */
10541  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10542  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10543  SCIP_Longint** demands, /**< pointer to array storing the demands */
10544  int* ndemands /**< pointer to store the number of different demands */
10545  )
10546 {
10547  int startindex;
10548  int ncountedvars;
10549 
10550  assert(demands != NULL);
10551  assert(ndemands != NULL);
10552 
10553  ncountedvars = 0;
10554  startindex = nstarted - 1;
10555 
10556  *ndemands = 0;
10557 
10558  /* search for the (nstarted - nfinished) jobs which are active at curtime */
10559  while( nstarted - nfinished > ncountedvars )
10560  {
10561  SCIP_VAR* var;
10562  int endtime;
10563  int varidx;
10564 
10565  /* collect job information */
10566  varidx = startindices[startindex];
10567  assert(varidx >= 0 && varidx < consdata->nvars);
10568 
10569  var = consdata->vars[varidx];
10570  assert(var != NULL);
10571 
10572  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10573 
10574  /* check the end time of this job is larger than the curtime; in this case the job is still running */
10575  if( endtime > curtime )
10576  {
10577  if( consdata->demands[varidx] < consdata->capacity )
10578  {
10579  (*demands)[*ndemands] = consdata->demands[varidx];
10580  (*ndemands)++;
10581  }
10582  ncountedvars++;
10583  }
10584 
10585  startindex--;
10586  }
10587 }
10588 
10589 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10590  * constraint
10591  */
10592 static
10594  SCIP* scip, /**< SCIP data structure */
10595  SCIP_CONS* cons, /**< constraint to be checked */
10596  int* startindices, /**< permutation with rspect to the start times */
10597  int curtime, /**< current point in time */
10598  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10599  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10600  int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10601  )
10602 {
10603  SCIP_CONSDATA* consdata;
10604  SCIP_Longint* demands;
10605  SCIP_Real* profits;
10606  int* items;
10607  int ndemands;
10608  SCIP_Bool success;
10609  SCIP_Real solval;
10610  int j;
10611  assert(nstarted > nfinished);
10612 
10613  consdata = SCIPconsGetData(cons);
10614  assert(consdata != NULL);
10615  assert(consdata->nvars > 0);
10616  assert(consdata->capacity > 0);
10617 
10618  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10619  ndemands = 0;
10620 
10621  /* get demand array to initialize knapsack problem */
10622  collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands);
10623 
10624  /* create array for profits */
10625  SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10626  SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10627  for( j = 0; j < ndemands; ++j )
10628  {
10629  profits[j] = (SCIP_Real) demands[j];
10630  items[j] = j;/* this is only a dummy value*/
10631  }
10632 
10633  /* solve knapsack problem and get maximum capacity usage <= capacity */
10634  SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10635  items, NULL, NULL, NULL, NULL, &solval, &success) );
10636 
10637  assert(SCIPisFeasIntegral(scip, solval));
10638 
10639  /* store result */
10640  *bestcapacity = SCIPconvertRealToInt(scip, solval);
10641 
10642  SCIPfreeBufferArray(scip, &items);
10643  SCIPfreeBufferArray(scip, &profits);
10644  SCIPfreeBufferArray(scip, &demands);
10645 
10646  return SCIP_OKAY;
10647 }
10648 
10649 /** try to tighten the capacity
10650  * -- using DP for knapsack, we find the maximum possible capacity usage
10651  * -- neglects hmin and hmax, such that it is also able to check solutions globally
10652  */
10653 static
10655  SCIP* scip, /**< SCIP data structure */
10656  SCIP_CONS* cons, /**< cumulative constraint */
10657  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10658  int* nchgsides /**< pointer to store the number of changed sides */
10659  )
10660 {
10661  SCIP_CONSDATA* consdata;
10662  int* starttimes; /* stores when each job is starting */
10663  int* endtimes; /* stores when each job ends */
10664  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10665  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10666 
10667  int nvars; /* number of activities for this constraint */
10668  int freecapacity; /* remaining capacity */
10669  int curtime; /* point in time which we are just checking */
10670  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10671 
10672  int bestcapacity;
10673 
10674  int j;
10675 
10676  assert(scip != NULL);
10677  assert(cons != NULL);
10678  assert(nchgsides != NULL);
10679 
10680  consdata = SCIPconsGetData(cons);
10681  assert(consdata != NULL);
10682 
10683  nvars = consdata->nvars;
10684 
10685  /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10686  if( nvars <= 1 || consdata->capacity <= 1 )
10687  return SCIP_OKAY;
10688 
10689  assert(consdata->vars != NULL);
10690 
10691  SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10692  SCIPconsGetName(cons), consdata->capacity);
10693 
10694  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10695  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10696  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10697  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10698 
10699  /* create event point arrays */
10700  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10701  starttimes, endtimes, startindices, endindices, FALSE);
10702 
10703  bestcapacity = 1;
10704  endindex = 0;
10705  freecapacity = consdata->capacity;
10706 
10707  /* check each startpoint of a job whether the capacity is kept or not */
10708  for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10709  {
10710  curtime = starttimes[j];
10711  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10712 
10713  /* remove the capacity requirments for all job which start at the curtime */
10714  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10715 
10716  /* add the capacity requirments for all job which end at the curtime */
10717  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10718 
10719  assert(freecapacity <= consdata->capacity);
10720  assert(endindex <= nvars);
10721 
10722  /* endindex - points to the next job which will finish */
10723  /* j - points to the last job that has been released */
10724 
10725  /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10726  if( freecapacity < 0 )
10727  {
10728  int newcapacity;
10729 
10730  newcapacity = 1;
10731 
10732  /* get best possible upper bound on capacity usage */
10733  SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10734 
10735  /* update bestcapacity */
10736  bestcapacity = MAX(bestcapacity, newcapacity);
10737  SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10738  }
10739 
10740  /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10741  if( freecapacity > 0 && freecapacity != consdata->capacity )
10742  {
10743  bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10744  SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10745  }
10746 
10747  /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10748  if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10749  {
10750  /* if demands[startindices[j]] == cap then exactly that job is running */
10751  SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10752  bestcapacity = consdata->capacity;
10753  break;
10754  }
10755  } /*lint --e{850}*/
10756 
10757  /* free all buffer arrays */
10758  SCIPfreeBufferArray(scip, &endindices);
10759  SCIPfreeBufferArray(scip, &startindices);
10760  SCIPfreeBufferArray(scip, &endtimes);
10761  SCIPfreeBufferArray(scip, &starttimes);
10762 
10763  /* check whether capacity can be tightened and whether demands need to be adjusted */
10764  if( bestcapacity < consdata->capacity )
10765  {
10766  SCIPdebug( int oldnchgcoefs = *nchgcoefs; )
10767 
10768  SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10769  SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10770 
10771  for( j = 0; j < nvars; ++j )
10772  {
10773  if( consdata->demands[j] == consdata->capacity )
10774  {
10775  consdata->demands[j] = bestcapacity;
10776  (*nchgcoefs)++;
10777  }
10778  }
10779 
10780  consdata->capacity = bestcapacity;
10781  (*nchgsides)++;
10782 
10783  SCIPdebug( SCIPdebugMsg(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs); )
10784 
10785  consdata->varbounds = FALSE;
10786  }
10787 
10788  return SCIP_OKAY;
10789 }
10790 
10791 /** tries to change coefficients:
10792  * demand_j < cap && all other parallel jobs in conflict
10793  * ==> set demand_j := cap
10794  */
10795 static
10797  SCIP* scip, /**< SCIP data structure */
10798  SCIP_CONS* cons, /**< cumulative constraint */
10799  int* nchgcoefs /**< pointer to count total number of changed coefficients */
10800  )
10801 {
10802  SCIP_CONSDATA* consdata;
10803  int nvars;
10804  int j;
10805  int oldnchgcoefs;
10806  int mindemand;
10807 
10808  assert(scip != NULL);
10809  assert(cons != NULL);
10810  assert(nchgcoefs != NULL);
10811 
10812  /* get constraint data for some parameter testings only! */
10813  consdata = SCIPconsGetData(cons);
10814  assert(consdata != NULL);
10815 
10816  nvars = consdata->nvars;
10817  oldnchgcoefs = *nchgcoefs;
10818 
10819  if( nvars <= 0 )
10820  return SCIP_OKAY;
10821 
10822  /* PRE1:
10823  * check all jobs j whether: r_j + r_min > capacity holds
10824  * if so: adjust r_j to capacity
10825  */
10826  mindemand = consdata->demands[0];
10827  for( j = 0; j < nvars; ++j )
10828  {
10829  mindemand = MIN(mindemand, consdata->demands[j]);
10830  }
10831 
10832  /*check each job */
10833  for( j = 0; j < nvars; ++j )
10834  {
10835  if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10836  {
10837  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10838  consdata->demands[j], consdata->capacity);
10839  consdata->demands[j] = consdata->capacity;
10840  (*nchgcoefs)++;
10841  }
10842  }
10843 
10844  /* PRE2:
10845  * check for each job (with d_j < cap)
10846  * whether it is disjunctive to all others over the time horizon
10847  */
10848  for( j = 0; j < nvars; ++j )
10849  {
10850  SCIP_Bool chgcoef;
10851  int est_j;
10852  int lct_j;
10853  int i;
10854 
10855  assert(consdata->demands[j] <= consdata->capacity);
10856 
10857  if( consdata->demands[j] == consdata->capacity )
10858  continue;
10859 
10860  chgcoef = TRUE;
10861 
10862  est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10863  lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10864 
10865  for( i = 0; i < nvars; ++i )
10866  {
10867  int est_i;
10868  int lct_i;
10869 
10870  if( i == j )
10871  continue;
10872 
10873  est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10874  lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10875 
10876  if( est_i >= lct_j || est_j >= lct_i )
10877  continue;
10878 
10879  if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10880  {
10881  chgcoef = FALSE;
10882  break;
10883  }
10884  }
10885 
10886  if( chgcoef )
10887  {
10888  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10889  consdata->demands[j], consdata->capacity);
10890  consdata->demands[j] = consdata->capacity;
10891  (*nchgcoefs)++;
10892  }
10893  }
10894 
10895  if( (*nchgcoefs) > oldnchgcoefs )
10896  {
10897  SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10898  (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10899  }
10900 
10901  return SCIP_OKAY;
10902 }
10903 
10904 #if 0
10905 /** try to reformulate constraint by replacing certain jobs */
10906 static
10907 SCIP_RETCODE reformulateCons(
10908  SCIP* scip, /**< SCIP data structure */
10909  SCIP_CONS* cons, /**< cumulative constraint */
10910  int* naggrvars /**< pointer to store the number of aggregated variables */
10911  )
10912 {
10913  SCIP_CONSDATA* consdata;
10914  int hmin;
10915  int hmax;
10916  int nvars;
10917  int v;
10918 
10919  consdata = SCIPconsGetData(cons);
10920  assert(cons != NULL);
10921 
10922  nvars = consdata->nvars;
10923  assert(nvars > 1);
10924 
10925  hmin = consdata->hmin;
10926  hmax = consdata->hmax;
10927  assert(hmin < hmax);
10928 
10929  for( v = 0; v < nvars; ++v )
10930  {
10931  SCIP_VAR* var;
10932  int duration;
10933  int est;
10934  int ect;
10935  int lst;
10936  int lct;
10937 
10938  var = consdata->vars[v];
10939  assert(var != NULL);
10940 
10941  duration = consdata->durations[v];
10942 
10943  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10944  ect = est + duration;
10945  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10946  lct = lst + duration;
10947 
10948  /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10949  assert(lst > hmin || ect < hmax);
10950 
10951  if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10952  {
10953  SCIP_VAR* aggrvar;
10954  char name[SCIP_MAXSTRLEN];
10955  SCIP_Bool infeasible;
10956  SCIP_Bool redundant;
10957  SCIP_Bool aggregated;
10958  int shift;
10959 
10960  shift = est - (hmin - lct + MIN(hmin, ect));
10961  assert(shift > 0);
10962  lst = hmin;
10963  duration = hmin - lct;
10964 
10965  SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10966  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10967 
10968  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10969  SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10971  SCIP_CALL( SCIPaddVar(scip, var) );
10972  SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10973 
10974  assert(!infeasible);
10975  assert(!redundant);
10976  assert(aggregated);
10977 
10978  /* replace variable */
10979  consdata->durations[v] = duration;
10980  consdata->vars[v] = aggrvar;
10981 
10982  /* remove and add locks */
10983  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10984  SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10985 
10986  SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10987 
10988  (*naggrvars)++;
10989  }
10990  }
10991 
10992  return SCIP_OKAY;
10993 }
10994 #endif
10995 
10996 /** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10997 static
10999  SCIP* scip, /**< SCIP data structure */
11000  SCIP_CONS* cons, /**< cumulative constraint */
11001  int* naddconss /**< pointer to store the number of added constraints */
11002  )
11003 {
11004  SCIP_CONSDATA* consdata;
11005  SCIP_VAR** vars;
11006  int* durations;
11007  int* demands;
11008  int capacity;
11009  int halfcapacity;
11010  int mindemand;
11011  int nvars;
11012  int v;
11013 
11014  consdata = SCIPconsGetData(cons);
11015  assert(consdata != NULL);
11016 
11017  capacity = consdata->capacity;
11018 
11019  if( capacity == 1 )
11020  return SCIP_OKAY;
11021 
11022  SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
11023  SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
11024  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
11025 
11026  halfcapacity = capacity / 2;
11027  mindemand = consdata->capacity;
11028  nvars = 0;
11029 
11030  /* collect all jobs with demand larger than half of the capacity */
11031  for( v = 0; v < consdata->nvars; ++v )
11032  {
11033  if( consdata->demands[v] > halfcapacity )
11034  {
11035  vars[nvars] = consdata->vars[v];
11036  demands[nvars] = 1;
11037  durations[nvars] = consdata->durations[v];
11038  nvars++;
11039 
11040  mindemand = MIN(mindemand, consdata->demands[v]);
11041  }
11042  }
11043 
11044  if( nvars > 0 )
11045  {
11046  /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
11047  * job is still to large to be scheduled in parallel
11048  */
11049  for( v = 0; v < consdata->nvars; ++v )
11050  {
11051  if( consdata->demands[v] > halfcapacity )
11052  continue;
11053 
11054  if( mindemand + consdata->demands[v] > capacity )
11055  {
11056  demands[nvars] = 1;
11057  durations[nvars] = consdata->durations[v];
11058  vars[nvars] = consdata->vars[v];
11059  nvars++;
11060 
11061  /* @todo create one cumulative constraint and look for another small demand */
11062  break;
11063  }
11064  }
11065 
11066  /* creates cumulative constraint and adds it to problem */
11067  SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
11069  (*naddconss)++;
11070  }
11071 
11072  SCIPfreeBufferArray(scip, &demands);
11073  SCIPfreeBufferArray(scip, &durations);
11074  SCIPfreeBufferArray(scip, &vars);
11075 
11076  return SCIP_OKAY;
11077 }
11078 
11079 /** presolve given constraint */
11080 static
11082  SCIP* scip, /**< SCIP data structure */
11083  SCIP_CONS* cons, /**< cumulative constraint */
11084  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
11085  SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
11086  int* nfixedvars, /**< pointer to store the number of fixed variables */
11087 #if 0
11088  int* naggrvars, /**< pointer to counter which is increased by the number of deduced variable aggregations */
11089 #endif
11090  int* nchgbds, /**< pointer to store the number of changed bounds */
11091  int* ndelconss, /**< pointer to store the number of deleted constraints */
11092  int* naddconss, /**< pointer to store the number of added constraints */
11093  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
11094  int* nchgsides, /**< pointer to store the number of changed sides */
11095  SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
11096  SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
11097  )
11098 {
11099  assert(!SCIPconsIsDeleted(cons));
11100 
11101  /* only perform dual reductions on model constraints */
11102  if( conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) )
11103  {
11104  /* computes the effective horizon and checks if the constraint can be decomposed */
11105  SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11106 
11107  if( SCIPconsIsDeleted(cons) )
11108  return SCIP_OKAY;
11109 
11110  /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11111  * fixings (dual reductions)
11112  */
11113  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11114  {
11115  SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11116 
11117  if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11118  return SCIP_OKAY;
11119  }
11120 
11121  SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11122 
11123  if( *cutoff || SCIPconsIsDeleted(cons) )
11124  return SCIP_OKAY;
11125  }
11126 
11127  /* remove jobs which have a demand larger than the capacity */
11128  SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11129  assert((*cutoff) || checkDemands(scip, cons));
11130 
11131  if( *cutoff )
11132  return SCIP_OKAY;
11133 
11134  if( conshdlrdata->normalize )
11135  {
11136  /* divide demands by their greatest common divisor */
11137  normalizeDemands(scip, cons, nchgcoefs, nchgsides);
11138  }
11139 
11140  /* delete constraint with one job */
11141  SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11142 
11143  if( *cutoff || SCIPconsIsDeleted(cons) )
11144  return SCIP_OKAY;
11145 
11146  if( conshdlrdata->coeftightening )
11147  {
11148  /* try to tighten the capacity */
11149  SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11150 
11151  /* try to tighten the coefficients */
11152  SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11153  }
11154 
11155  assert(checkDemands(scip, cons) || *cutoff);
11156 
11157 #if 0
11158  SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11159 #endif
11160 
11161  return SCIP_OKAY;
11162 }
11163 
11164 /**@name TClique Graph callbacks
11165  *
11166  * @{
11167  */
11168 
11169 /** tclique graph data */
11170 struct TCLIQUE_Graph
11171 {
11172  SCIP_VAR** vars; /**< start time variables each of them is a node */
11173  SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11174  SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11175  SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11176  TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11177  int* ninarcs; /**< number if in arcs for the precedence graph */
11178  int* noutarcs; /**< number if out arcs for the precedence graph */
11179  int* durations; /**< for each node the duration of the corresponding job */
11180  int nnodes; /**< number of nodes */
11181  int size; /**< size of the array */
11182 };
11183 
11184 /** gets number of nodes in the graph */
11185 static
11186 TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11188  assert(tcliquegraph != NULL);
11189 
11190  return tcliquegraph->nnodes;
11191 }
11192 
11193 /** gets weight of nodes in the graph */
11194 static
11195 TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11197  assert(tcliquegraph != NULL);
11198 
11199  return tcliquegraph->weights;
11200 }
11201 
11202 /** returns, whether the edge (node1, node2) is in the graph */
11203 static
11204 TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11206  assert(tcliquegraph != NULL);
11207  assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11208  assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11209 
11210  /* check if an arc exits in the precedence graph */
11211  if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11212  return TRUE;
11213 
11214  /* check if an edge exits in the non-overlapping graph */
11215  if( tcliquegraph->demandmatrix[node1][node2] )
11216  return TRUE;
11217 
11218  return FALSE;
11219 }
11220 
11221 /** selects all nodes from a given set of nodes which are adjacent to a given node
11222  * and returns the number of selected nodes
11223  */
11224 static
11225 TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11227  int nadjnodes;
11228  int i;
11229 
11230  assert(tcliquegraph != NULL);
11231  assert(0 <= node && node < tcliquegraph->nnodes);
11232  assert(nnodes == 0 || nodes != NULL);
11233  assert(adjnodes != NULL);
11234 
11235  nadjnodes = 0;
11236 
11237  for( i = 0; i < nnodes; i++ )
11238  {
11239  /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11240  assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11241  assert(i == 0 || nodes[i-1] < nodes[i]);
11242 
11243  /* check if an edge exists */
11244  if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11245  {
11246  /* current node is adjacent to given node */
11247  adjnodes[nadjnodes] = nodes[i];
11248  nadjnodes++;
11249  }
11250  }
11251 
11252  return nadjnodes;
11253 }
11254 
11255 /** generates cuts using a clique found by algorithm for maximum weight clique
11256  * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11257  */
11258 static
11259 TCLIQUE_NEWSOL(tcliqueNewsolClique)
11260 { /*lint --e{715}*/
11261  SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11262 }
11263 
11264 /** print the tclique graph */
11265 #if 0
11266 static
11267 void tcliquePrint(
11268  SCIP* scip, /**< SCIP data structure */
11269  TCLIQUE_GRAPH* tcliquegraph /**< tclique graph */
11270  )
11271 {
11272  int nnodes;
11273  int i;
11274  int j;
11275 
11276  nnodes = tcliquegraph->nnodes;
11277 
11278  for( i = 0; i < nnodes; ++i )
11279  {
11280  for( j = 0; j < nnodes; ++j )
11281  {
11282  SCIPinfoMessage(scip, NULL, "(%d/%d) ", tcliquegraph->precedencematrix[i][j], tcliquegraph->demandmatrix[i][j]);
11283  }
11284  SCIPinfoMessage(scip, NULL, "\n");
11285  }
11286 }
11287 #endif
11288 
11289 /** @} */
11290 
11291 /** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11292  * job corresponding to variable bound variable (vlbvar)
11293  *
11294  * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11295  */
11296 static
11298  SCIP* scip, /**< SCIP data structure */
11299  SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11300  SCIP_Real vlbcoef, /**< variable bound coefficient */
11301  SCIP_Real vlbconst, /**< variable bound constant */
11302  int duration /**< duration of the variable bound variable */
11303  )
11304 {
11305  if( SCIPisEQ(scip, vlbcoef, 1.0) )
11306  {
11307  if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11308  {
11309  /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11310  return TRUE;
11311  }
11312  }
11313  else
11314  {
11315  SCIP_Real bound;
11316 
11317  bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11318 
11319  if( SCIPisLT(scip, vlbcoef, 1.0) )
11320  {
11321  SCIP_Real ub;
11322 
11323  ub = SCIPvarGetUbLocal(vlbvar);
11324 
11325  /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11326  if( SCIPisLE(scip, ub, bound) )
11327  return TRUE;
11328  }
11329  else
11330  {
11331  SCIP_Real lb;
11332 
11333  assert(SCIPisGT(scip, vlbcoef, 1.0));
11334 
11335  lb = SCIPvarGetLbLocal(vlbvar);
11336 
11337  /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11338  if( SCIPisGE(scip, lb, bound) )
11339  return TRUE;
11340  }
11341  }
11342 
11343  return FALSE;
11344 }
11345 
11346 /** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11347  * job corresponding to variable which is bounded (var)
11348  *
11349  * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11350  */
11351 static
11353  SCIP* scip, /**< SCIP data structure */
11354  SCIP_VAR* var, /**< variable which is bound from above */
11355  SCIP_Real vubcoef, /**< variable bound coefficient */
11356  SCIP_Real vubconst, /**< variable bound constant */
11357  int duration /**< duration of the variable which is bounded from above */
11358  )
11359 {
11360  SCIP_Real vlbcoef;
11361  SCIP_Real vlbconst;
11362 
11363  /* convert the variable upper bound into an variable lower bound */
11364  vlbcoef = 1.0 / vubcoef;
11365  vlbconst = -vubconst / vubcoef;
11366 
11367  return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11368 }
11369 
11370 /** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11371  * others an index larger than the number if active variables
11372  */
11373 static
11375  SCIP* scip, /**< SCIP data structure */
11376  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11377  SCIP_VAR* var, /**< variable for which we want the index */
11378  int* idx /**< pointer to store the index */
11379  )
11380 {
11381  (*idx) = SCIPvarGetProbindex(var);
11382 
11383  if( (*idx) == -1 )
11384  {
11385  if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11386  {
11387  (*idx) = SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var);
11388  }
11389  else
11390  {
11391  int pos;
11392  int v;
11393 
11394  /**@todo we might want to add the aggregation path to graph */
11395 
11396  /* check if we have to realloc memory */
11397  if( tcliquegraph->size == tcliquegraph->nnodes )
11398  {
11399  int size;
11400 
11401  size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11402  tcliquegraph->size = size;
11403 
11404  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11405  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11406  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11407  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11408  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11409 
11410  for( v = 0; v < tcliquegraph->nnodes; ++v )
11411  {
11412  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11413  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11414  }
11415  }
11416  assert(tcliquegraph->nnodes < tcliquegraph->size);
11417 
11418  pos = tcliquegraph->nnodes;
11419  assert(pos >= 0);
11420 
11421  tcliquegraph->durations[pos] = 0;
11422  tcliquegraph->weights[pos] = 0;
11423  tcliquegraph->vars[pos] = var;
11424 
11425  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11426  BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11427 
11428  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11429  BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11430 
11431  SCIP_CALL( SCIPhashmapInsertInt(tcliquegraph->varmap, (void*)var, pos) );
11432 
11433  tcliquegraph->nnodes++;
11434 
11435  for( v = 0; v < tcliquegraph->nnodes; ++v )
11436  {
11437  tcliquegraph->precedencematrix[v][pos] = 0;
11438  tcliquegraph->demandmatrix[v][pos] = 0;
11439  }
11440 
11441  (*idx) = tcliquegraph->nnodes;
11442  }
11443  }
11444  else
11445  {
11446  assert(*idx == SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var));
11447  }
11448 
11449  assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11450 
11451  return SCIP_OKAY;
11452 }
11453 
11454 /** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11455  *
11456  * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11457  * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11458  *
11459  * (i) b = 1 and c >= d
11460  * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11461  * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11462  *
11463  */
11464 static
11466  SCIP* scip, /**< SCIP data structure */
11467  TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11468  )
11469 {
11470  SCIP_VAR** vars;
11471  int nvars;
11472  int v;
11473 
11474  vars = SCIPgetVars(scip);
11475  nvars = SCIPgetNVars(scip);
11476 
11477  /* try to project each arc of the variable bound graph to precedence condition */
11478  for( v = 0; v < nvars; ++v )
11479  {
11480  SCIP_VAR** vbdvars;
11481  SCIP_VAR* var;
11482  SCIP_Real* vbdcoefs;
11483  SCIP_Real* vbdconsts;
11484  int nvbdvars;
11485  int idx1;
11486  int b;
11487 
11488  var = vars[v];
11489  assert(var != NULL);
11490 
11491  SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11492  assert(idx1 >= 0);
11493 
11494  if( tcliquegraph->durations[idx1] == 0 )
11495  continue;
11496 
11497  vbdvars = SCIPvarGetVlbVars(var);
11498  vbdcoefs = SCIPvarGetVlbCoefs(var);
11499  vbdconsts = SCIPvarGetVlbConstants(var);
11500  nvbdvars = SCIPvarGetNVlbs(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( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11513  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11514  }
11515 
11516  vbdvars = SCIPvarGetVubVars(var);
11517  vbdcoefs = SCIPvarGetVubCoefs(var);
11518  vbdconsts = SCIPvarGetVubConstants(var);
11519  nvbdvars = SCIPvarGetNVubs(var);
11520 
11521  for( b = 0; b < nvbdvars; ++b )
11522  {
11523  int idx2;
11524 
11525  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11526  assert(idx2 >= 0);
11527 
11528  if( tcliquegraph->durations[idx2] == 0 )
11529  continue;
11530 
11531  if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11532  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11533  }
11534 
11535  for( b = v+1; b < nvars; ++b )
11536  {
11537  int idx2;
11538 
11539  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11540  assert(idx2 >= 0);
11541 
11542  if( tcliquegraph->durations[idx2] == 0 )
11543  continue;
11544 
11545  /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11546  if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11547  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11548 
11549  /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11550  if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11551  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11552  }
11553  }
11554 
11555  return SCIP_OKAY;
11556 }
11557 
11558 /** compute the transitive closer of the given graph and the number of in and out arcs */
11559 static
11560 void transitiveClosure(
11561  SCIP_Bool** adjmatrix, /**< adjacent matrix */
11562  int* ninarcs, /**< array to store the number of in arcs */
11563  int* noutarcs, /**< array to store the number of out arcs */
11564  int nnodes /**< number if nodes */
11565  )
11566 {
11567  int i;
11568  int j;
11569  int k;
11570 
11571  for( i = 0; i < nnodes; ++i )
11572  {
11573  for( j = 0; j < nnodes; ++j )
11574  {
11575  if( adjmatrix[i][j] )
11576  {
11577  ninarcs[j]++;
11578  noutarcs[i]++;
11579 
11580  for( k = 0; k < nnodes; ++k )
11581  {
11582  if( adjmatrix[j][k] )
11583  adjmatrix[i][k] = TRUE;
11584  }
11585  }
11586  }
11587  }
11588 }
11589 
11590 /** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11591 static
11593  SCIP* scip, /**< SCIP data structure */
11594  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11595  SCIP_CONS** conss, /**< array of cumulative constraints */
11596  int nconss /**< number of cumulative constraints */
11597  )
11598 {
11599  int c;
11600 
11601  /* use the cumulative constraints to initialize the none overlapping graph */
11602  for( c = 0; c < nconss; ++c )
11603  {
11604  SCIP_CONSDATA* consdata;
11605  SCIP_VAR** vars;
11606  int* demands;
11607  int capacity;
11608  int nvars;
11609  int i;
11610 
11611  consdata = SCIPconsGetData(conss[c]);
11612  assert(consdata != NULL);
11613 
11614  vars = consdata->vars;
11615  demands = consdata->demands;
11616 
11617  nvars = consdata->nvars;
11618  capacity = consdata->capacity;
11619 
11620  SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11621 
11622  /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11623  for( i = 0; i < nvars; ++i )
11624  {
11625  int idx1;
11626  int j;
11627 
11628  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11629  assert(idx1 >= 0);
11630 
11631  if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11632  continue;
11633 
11634  for( j = i+1; j < nvars; ++j )
11635  {
11636  assert(consdata->durations[j] > 0);
11637 
11638  if( demands[i] + demands[j] > capacity )
11639  {
11640  int idx2;
11641  int est1;
11642  int est2;
11643  int lct1;
11644  int lct2;
11645 
11646  /* check if the effective horizon is large enough */
11647  est1 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[i]));
11648  est2 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[j]));
11649 
11650  /* at least one of the jobs needs to start at hmin or later */
11651  if( est1 < consdata->hmin && est2 < consdata->hmin )
11652  continue;
11653 
11654  lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11655  lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11656 
11657  /* at least one of the jobs needs to finish not later then hmin */
11658  if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11659  continue;
11660 
11661  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11662  assert(idx2 >= 0);
11663  assert(idx1 != idx2);
11664 
11665  if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11666  continue;
11667 
11668  SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11669 
11670  assert(tcliquegraph->durations[idx1] > 0);
11671  assert(tcliquegraph->durations[idx2] > 0);
11672 
11673  tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11674  tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11675  }
11676  }
11677  }
11678  }
11679 
11680  return SCIP_OKAY;
11681 }
11682 
11683 /** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11684  * of jobs cannot run in parallel
11685  */
11686 static
11688  SCIP* scip, /**< SCIP data structure */
11689  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11690  SCIP_CONS** conss, /**< array of cumulative constraints */
11691  int nconss /**< number of cumulative constraints */
11692  )
11693 {
11694  assert(scip != NULL);
11695  assert(tcliquegraph != NULL);
11696 
11697  /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11698  SCIP_CALL( projectVbd(scip, tcliquegraph) );
11699 
11700  /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11701  transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11702 
11703  /* constraints non-overlapping graph */
11704  SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11705 
11706  return SCIP_OKAY;
11707 }
11708 
11709 /** create cumulative constraint from conflict set */
11710 static
11712  SCIP* scip, /**< SCIP data structure */
11713  const char* name, /**< constraint name */
11714  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11715  int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11716  int ncliquenodes /**< number of nodes in the clique */
11717  )
11718 {
11719  SCIP_CONS* cons;
11720  SCIP_VAR** vars;
11721  int* durations;
11722  int* demands;
11723  int v;
11724 
11725  SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11726  SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11727  SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11728 
11729  SCIPsortInt(cliquenodes, ncliquenodes);
11730 
11731  /* collect variables, durations, and demands */
11732  for( v = 0; v < ncliquenodes; ++v )
11733  {
11734  durations[v] = tcliquegraph->durations[cliquenodes[v]];
11735  assert(durations[v] > 0);
11736  demands[v] = 1;
11737  vars[v] = tcliquegraph->vars[cliquenodes[v]];
11738  }
11739 
11740  /* create (unary) cumulative constraint */
11741  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11743 
11744  SCIP_CALL( SCIPaddCons(scip, cons) );
11745  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11746 
11747  /* free buffers */
11748  SCIPfreeBufferArray(scip, &demands);
11749  SCIPfreeBufferArray(scip, &durations);
11750  SCIPfreeBufferArray(scip, &vars);
11751 
11752  return SCIP_OKAY;
11753 }
11754 
11755 /** search for cumulative constrainst */
11756 static
11758  SCIP* scip, /**< SCIP data structure */
11759  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11760  int* naddconss /**< pointer to store the number of added constraints */
11761  )
11762 {
11763  TCLIQUE_STATUS tcliquestatus;
11764  SCIP_Bool* precedencerow;
11765  SCIP_Bool* precedencecol;
11766  SCIP_Bool* demandrow;
11767  SCIP_Bool* demandcol;
11768  SCIP_HASHTABLE* covered;
11769  int* cliquenodes;
11770  int ncliquenodes;
11771  int cliqueweight;
11772  int ntreenodes;
11773  int nnodes;
11774  int nconss;
11775  int v;
11776 
11777  nnodes = tcliquegraph->nnodes;
11778  nconss = 0;
11779 
11780  /* initialize the weight of each job with its duration */
11781  for( v = 0; v < nnodes; ++v )
11782  {
11783  tcliquegraph->weights[v] = tcliquegraph->durations[v];
11784  }
11785 
11786  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11787  SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11788  SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11789  SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11790  SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11791 
11792  /* create a hash table to store all start time variables which are already covered by at least one clique */
11793  SCIP_CALL( SCIPhashtableCreate(&covered, SCIPblkmem(scip), nnodes,
11794  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11795 
11796  /* for each variables/job we are ... */
11797  for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11798  {
11799  char name[SCIP_MAXSTRLEN];
11800  int c;
11801 
11802  /* jobs with zero durations are skipped */
11803  if( tcliquegraph->durations[v] == 0 )
11804  continue;
11805 
11806  /* check if the start time variable is already covered by at least one clique */
11807  if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11808  continue;
11809 
11810  SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11811 
11812  /* temporarily remove the connection via the precedence graph */
11813  for( c = 0; c < nnodes; ++c )
11814  {
11815  precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11816  precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11817 
11818  demandrow[c] = tcliquegraph->demandmatrix[v][c];
11819  demandcol[c] = tcliquegraph->demandmatrix[c][v];
11820 
11821 #if 0
11822  if( precedencerow[c] || precedencecol[c] )
11823  {
11824  tcliquegraph->demandmatrix[v][c] = FALSE;
11825  tcliquegraph->demandmatrix[c][v] = FALSE;
11826  }
11827 #endif
11828 
11829  tcliquegraph->precedencematrix[c][v] = FALSE;
11830  tcliquegraph->precedencematrix[v][c] = FALSE;
11831  }
11832 
11833  /* find (heuristically) maximum cliques which includes node v */
11834  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11835  tcliquegraph, tcliqueNewsolClique, NULL,
11836  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11837  10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11838 
11839  SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11840 
11841  if( ncliquenodes == 1 )
11842  continue;
11843 
11844  /* construct constraint name */
11845  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11846 
11847  SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11848  nconss++;
11849 
11850  /* all start time variable to covered hash table */
11851  for( c = 0; c < ncliquenodes; ++c )
11852  {
11853  SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11854  }
11855 
11856  /* copy the precedence relations back */
11857  for( c = 0; c < nnodes; ++c )
11858  {
11859  tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11860  tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11861 
11862  tcliquegraph->demandmatrix[v][c] = demandrow[c];
11863  tcliquegraph->demandmatrix[c][v] = demandcol[c];
11864  }
11865  }
11866 
11867  SCIPhashtableFree(&covered);
11868 
11869  SCIPfreeBufferArray(scip, &demandcol);
11870  SCIPfreeBufferArray(scip, &demandrow);
11871  SCIPfreeBufferArray(scip, &precedencecol);
11872  SCIPfreeBufferArray(scip, &precedencerow);
11873  SCIPfreeBufferArray(scip, &cliquenodes);
11874 
11875  (*naddconss) += nconss;
11876 
11877  /* for the statistic we count the number added disjunctive constraints */
11878  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11879 
11880  return SCIP_OKAY;
11881 }
11882 
11883 /** create precedence constraint (as variable bound constraint */
11884 static
11886  SCIP* scip, /**< SCIP data structure */
11887  const char* name, /**< constraint name */
11888  SCIP_VAR* var, /**< variable x that has variable bound */
11889  SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11890  int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11891  )
11892 {
11893  SCIP_CONS* cons;
11894 
11895  /* create variable bound constraint */
11896  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11898 
11899  SCIPdebugPrintCons(scip, cons, NULL);
11900 
11901  /* add constraint to problem and release it */
11902  SCIP_CALL( SCIPaddCons(scip, cons) );
11903  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11904 
11905  return SCIP_OKAY;
11906 }
11907 
11908 /** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11909 static
11911  SCIP* scip, /**< SCIP data structure */
11912  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11913  int source, /**< index of the source node */
11914  int sink, /**< index of the sink node */
11915  int* naddconss /**< pointer to store the number of added constraints */
11916  )
11917 {
11918  TCLIQUE_WEIGHT cliqueweight;
11919  TCLIQUE_STATUS tcliquestatus;
11920  SCIP_VAR** vars;
11921  int* cliquenodes;
11922  int nnodes;
11923  int lct;
11924  int est;
11925  int i;
11926 
11927  int ntreenodes;
11928  int ncliquenodes;
11929 
11930  /* check if source and sink are connencted */
11931  if( !tcliquegraph->precedencematrix[source][sink] )
11932  return SCIP_OKAY;
11933 
11934  nnodes = tcliquegraph->nnodes;
11935  vars = tcliquegraph->vars;
11936 
11937  /* reset the weights to zero */
11938  BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11939 
11940  /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11941  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11942  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[sink]));
11943 
11944  /* weight all jobs which run for sure between source and sink with their duration */
11945  for( i = 0; i < nnodes; ++i )
11946  {
11947  SCIP_VAR* var;
11948  int duration;
11949 
11950  var = vars[i];
11951  assert(var != NULL);
11952 
11953  duration = tcliquegraph->durations[i];
11954 
11955  if( i == source || i == sink )
11956  {
11957  /* source and sink are not weighted */
11958  tcliquegraph->weights[i] = 0;
11959  }
11960  else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11961  {
11962  /* job i runs after source and before sink */
11963  tcliquegraph->weights[i] = duration;
11964  }
11965  else if( lct <= SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var))
11966  && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11967  {
11968  /* job i run in between due the bounds of the start time variables */
11969  tcliquegraph->weights[i] = duration;
11970  }
11971  else
11972  tcliquegraph->weights[i] = 0;
11973  }
11974 
11975  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11976 
11977  /* find (heuristically) maximum cliques */
11978  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11979  tcliquegraph, tcliqueNewsolClique, NULL,
11980  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11981  10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11982 
11983  if( ncliquenodes > 1 )
11984  {
11985  char name[SCIP_MAXSTRLEN];
11986  int distance;
11987 
11988  /* construct constraint name */
11989  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11990 
11991  /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11992  * duration of the source job
11993  */
11994  distance = cliqueweight + tcliquegraph->durations[source];
11995 
11996  SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11997  (*naddconss)++;
11998  }
11999 
12000  SCIPfreeBufferArray(scip, &cliquenodes);
12001 
12002  return SCIP_OKAY;
12003 }
12004 
12005 /** search for precedence constraints
12006  *
12007  * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
12008  * corresponding two jobs
12009  */
12010 static
12012  SCIP* scip, /**< SCIP data structure */
12013  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
12014  int* naddconss /**< pointer to store the number of added constraints */
12015  )
12016 {
12017  int* sources;
12018  int* sinks;
12019  int nconss;
12020  int nnodes;
12021  int nsources;
12022  int nsinks;
12023  int i;
12024 
12025  nnodes = tcliquegraph->nnodes;
12026  nconss = 0;
12027 
12028  nsources = 0;
12029  nsinks = 0;
12030 
12031  SCIP_CALL( SCIPallocBufferArray(scip, &sources, nnodes) );
12032  SCIP_CALL( SCIPallocBufferArray(scip, &sinks, nnodes) );
12033 
12034  /* first collect all sources and sinks */
12035  for( i = 0; i < nnodes; ++i )
12036  {
12037  if( tcliquegraph->ninarcs[i] == 0 )
12038  {
12039  sources[nsources] = i;
12040  nsources++;
12041  }
12042 
12043  if( tcliquegraph->ninarcs[i] == 0 )
12044  {
12045  sinks[nsinks] = i;
12046  nsinks++;
12047  }
12048  }
12049 
12050  /* compute for each node a minimum distance to each sources and each sink */
12051  for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
12052  {
12053  int j;
12054 
12055  for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
12056  {
12057  SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
12058  }
12059 
12060  for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
12061  {
12062  SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
12063  }
12064  }
12065 
12066  (*naddconss) += nconss;
12067 
12068  /* for the statistic we count the number added variable constraints */
12069  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
12070 
12071  SCIPfreeBufferArray(scip, &sinks);
12072  SCIPfreeBufferArray(scip, &sources);
12073 
12074  return SCIP_OKAY;
12075 }
12076 
12077 /** initialize the assumed durations for each variable */
12078 static
12080  SCIP* scip, /**< SCIP data structure */
12081  TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
12082  SCIP_CONS** conss, /**< cumulative constraints */
12083  int nconss /**< number of cumulative constraints */
12084  )
12085 {
12086  int c;
12087 
12088  /* use the cumulative structure to define the duration we are using for each job */
12089  for( c = 0; c < nconss; ++c )
12090  {
12091  SCIP_CONSDATA* consdata;
12092  SCIP_VAR** vars;
12093  int nvars;
12094  int v;
12095 
12096  consdata = SCIPconsGetData(conss[c]);
12097  assert(consdata != NULL);
12098 
12099  vars = consdata->vars;
12100  nvars = consdata->nvars;
12101 
12102  for( v = 0; v < nvars; ++v )
12103  {
12104  int idx;
12105 
12106  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12107  assert(idx >= 0);
12108 
12109  /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12110  * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12111  * general this is not the case. Therefore, the question would be which duration should be used?
12112  */
12113  tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12114  assert(tcliquegraph->durations[idx] > 0);
12115  }
12116  }
12117 
12118  return SCIP_OKAY;
12119 }
12120 
12121 /** create tclique graph */
12122 static
12124  SCIP* scip, /**< SCIP data structure */
12125  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12126  )
12127 {
12128  SCIP_VAR** vars;
12129  SCIP_HASHMAP* varmap;
12130  SCIP_Bool** precedencematrix;
12131  SCIP_Bool** demandmatrix;
12132  int* ninarcs;
12133  int* noutarcs;
12134  int* durations;
12135  int* weights;
12136  int nvars;
12137  int v;
12138 
12139  vars = SCIPgetVars(scip);
12140  nvars = SCIPgetNVars(scip);
12141 
12142  /* allocate memory for the tclique graph data structure */
12143  SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12144 
12145  /* create the variable mapping hash map */
12146  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
12147 
12148  /* each active variables get a node in the graph */
12149  SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12150 
12151  /* allocate memory for the projected variables bound graph and the none overlapping graph */
12152  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12153  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12154 
12155  /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12156  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12157  BMSclearMemoryArray(weights, nvars);
12158 
12159  /* array to store the number of in arc of the precedence graph */
12160  SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12161  BMSclearMemoryArray(ninarcs, nvars);
12162 
12163  /* array to store the number of out arc of the precedence graph */
12164  SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12165  BMSclearMemoryArray(noutarcs, nvars);
12166 
12167  /* array to store the used duration for each node */
12168  SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12169  BMSclearMemoryArray(durations, nvars);
12170 
12171  for( v = 0; v < nvars; ++v )
12172  {
12173  SCIP_VAR* var;
12174 
12175  var = vars[v];
12176  assert(var != NULL);
12177 
12178  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12179  BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12180 
12181  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12182  BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12183 
12184  /* insert all active variables into the garph */
12185  assert(SCIPvarGetProbindex(var) == v);
12186  SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)var, v) );
12187  }
12188 
12189  (*tcliquegraph)->nnodes = nvars;
12190  (*tcliquegraph)->varmap = varmap;
12191  (*tcliquegraph)->precedencematrix = precedencematrix;
12192  (*tcliquegraph)->demandmatrix = demandmatrix;
12193  (*tcliquegraph)->weights = weights;
12194  (*tcliquegraph)->ninarcs = ninarcs;
12195  (*tcliquegraph)->noutarcs = noutarcs;
12196  (*tcliquegraph)->durations = durations;
12197  (*tcliquegraph)->size = nvars;
12198 
12199  return SCIP_OKAY;
12200 }
12201 
12202 /** frees the tclique graph */
12203 static
12204 void freeTcliqueGraph(
12205  SCIP* scip, /**< SCIP data structure */
12206  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12207  )
12208 {
12209  int v;
12210 
12211  for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12212  {
12213  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12214  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12215  }
12216 
12217  SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12218  SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12219  SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12220  SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12221  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12222  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12223  SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12224  SCIPhashmapFree(&(*tcliquegraph)->varmap);
12225 
12226  SCIPfreeBuffer(scip, tcliquegraph);
12227 }
12228 
12229 /** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12230  * constrains (disjunctive constraint)
12231  */
12232 static
12234  SCIP* scip, /**< SCIP data structure */
12235  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12236  SCIP_CONS** conss, /**< array of cumulative constraints */
12237  int nconss, /**< number of cumulative constraints */
12238  int* naddconss /**< pointer to store the number of added constraints */
12239  )
12240 {
12241  TCLIQUE_GRAPH* tcliquegraph;
12242 
12243  /* create tclique graph */
12244  SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12245 
12246  /* define for each job a duration */
12247  SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12248 
12249  /* constuct incompatibility graph */
12250  SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12251 
12252  /* search for new precedence constraints */
12253  if( conshdlrdata->detectvarbounds )
12254  {
12255  SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12256  }
12257 
12258  /* search for new cumulative constraints */
12259  if( conshdlrdata->detectdisjunctive )
12260  {
12261  SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12262  }
12263 
12264  /* free tclique graph data structure */
12265  freeTcliqueGraph(scip, &tcliquegraph);
12266 
12267  return SCIP_OKAY;
12268 }
12269 
12270 /** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12271 static
12273  SCIP_CONSDATA* consdata /**< cumulative constraint data */
12274  )
12275 {
12276  SCIP_VAR** vars;
12277  int nvars;
12278  int v;
12279 
12280  if( consdata->validsignature )
12281  return;
12282 
12283  vars = consdata->vars;
12284  nvars = consdata->nvars;
12285 
12286  for( v = 0; v < nvars; ++v )
12287  {
12288  consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12289  }
12290 
12291  consdata->validsignature = TRUE;
12292 }
12293 
12294 /** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12295 static
12296 SCIP_DECL_SORTINDCOMP(consdataCompVar)
12297 { /*lint --e{715}*/
12298  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12299 
12300  assert(consdata != NULL);
12301  assert(0 <= ind1 && ind1 < consdata->nvars);
12302  assert(0 <= ind2 && ind2 < consdata->nvars);
12303 
12304  return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12305 }
12306 
12307 /** run a pairwise comparison */
12308 static
12310  SCIP* scip, /**< SCIP data structure */
12311  SCIP_CONS** conss, /**< array of cumulative constraints */
12312  int nconss, /**< number of cumulative constraints */
12313  int* ndelconss /**< pointer to store the number of deletedconstraints */
12314  )
12315 {
12316  int i;
12317  int j;
12318 
12319  for( i = 0; i < nconss; ++i )
12320  {
12321  SCIP_CONSDATA* consdata0;
12322  SCIP_CONS* cons0;
12323 
12324  cons0 = conss[i];
12325  assert(cons0 != NULL);
12326 
12327  consdata0 = SCIPconsGetData(cons0);
12328  assert(consdata0 != NULL);
12329 
12330  consdataCalcSignature(consdata0);
12331  assert(consdata0->validsignature);
12332 
12333  for( j = i+1; j < nconss; ++j )
12334  {
12335  SCIP_CONSDATA* consdata1;
12336  SCIP_CONS* cons1;
12337 
12338  cons1 = conss[j];
12339  assert(cons1 != NULL);
12340 
12341  consdata1 = SCIPconsGetData(cons1);
12342  assert(consdata1 != NULL);
12343 
12344  if( consdata0->capacity != consdata1->capacity )
12345  continue;
12346 
12347  consdataCalcSignature(consdata1);
12348  assert(consdata1->validsignature);
12349 
12350  if( (consdata1->signature & (~consdata0->signature)) == 0 )
12351  {
12352  SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12353  SCIPswapPointers((void**)&cons0, (void**)&cons1);
12354  assert((consdata0->signature & (~consdata1->signature)) == 0);
12355  }
12356 
12357  if( (consdata0->signature & (~consdata1->signature)) == 0 )
12358  {
12359  int* perm0;
12360  int* perm1;
12361  int v0;
12362  int v1;
12363 
12364  if( consdata0->nvars > consdata1->nvars )
12365  continue;
12366 
12367  if( consdata0->hmin < consdata1->hmin )
12368  continue;
12369 
12370  if( consdata0->hmax > consdata1->hmax )
12371  continue;
12372 
12373  SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12374  SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12375 
12376  /* call sorting method */
12377  SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12378  SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12379 
12380  for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12381  {
12382  SCIP_VAR* var0;
12383  SCIP_VAR* var1;
12384  int idx0;
12385  int idx1;
12386  int comp;
12387 
12388  idx0 = perm0[v0];
12389  idx1 = perm1[v1];
12390 
12391  var0 = consdata0->vars[idx0];
12392 
12393  var1 = consdata1->vars[idx1];
12394 
12395  comp = SCIPvarCompare(var0, var1);
12396 
12397  if( comp == 0 )
12398  {
12399  int duration0;
12400  int duration1;
12401  int demand0;
12402  int demand1;
12403 
12404  demand0 = consdata0->demands[idx0];
12405  duration0 = consdata0->durations[idx0];
12406 
12407  demand1 = consdata1->demands[idx1];
12408  duration1 = consdata1->durations[idx1];
12409 
12410  if( demand0 != demand1 )
12411  break;
12412 
12413  if( duration0 != duration1 )
12414  break;
12415 
12416  v0++;
12417  v1++;
12418  }
12419  else if( comp > 0 )
12420  v1++;
12421  else
12422  break;
12423  }
12424 
12425  if( v0 == consdata0->nvars )
12426  {
12427  if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12428  {
12429  initializeLocks(consdata1, TRUE);
12430  }
12431 
12432  /* coverity[swapped_arguments] */
12433  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12434 
12435  SCIP_CALL( SCIPdelCons(scip, cons0) );
12436  (*ndelconss)++;
12437  }
12438 
12439  SCIPfreeBufferArray(scip, &perm1);
12440  SCIPfreeBufferArray(scip, &perm0);
12441  }
12442  }
12443  }
12444 
12445  return SCIP_OKAY;
12446 }
12447 
12448 /** strengthen the variable bounds using the cumulative condition */
12449 static
12451  SCIP* scip, /**< SCIP data structure */
12452  SCIP_CONS* cons, /**< constraint to propagate */
12453  int* nchgbds, /**< pointer to store the number of changed bounds */
12454  int* naddconss /**< pointer to store the number of added constraints */
12455  )
12456 {
12457  SCIP_CONSDATA* consdata;
12458  SCIP_VAR** vars;
12459  int* durations;
12460  int* demands;
12461  int capacity;
12462  int nvars;
12463  int nconss;
12464  int i;
12465 
12466  consdata = SCIPconsGetData(cons);
12467  assert(consdata != NULL);
12468 
12469  /* check if the variable bounds got already strengthen by the cumulative constraint */
12470  if( consdata->varbounds )
12471  return SCIP_OKAY;
12472 
12473  vars = consdata->vars;
12474  durations = consdata->durations;
12475  demands = consdata->demands;
12476  capacity = consdata->capacity;
12477  nvars = consdata->nvars;
12478 
12479  nconss = 0;
12480 
12481  for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12482  {
12483  SCIP_VAR** vbdvars;
12484  SCIP_VAR* var;
12485  SCIP_Real* vbdcoefs;
12486  SCIP_Real* vbdconsts;
12487  int nvbdvars;
12488  int b;
12489  int j;
12490 
12491  var = consdata->vars[i];
12492  assert(var != NULL);
12493 
12494  vbdvars = SCIPvarGetVlbVars(var);
12495  vbdcoefs = SCIPvarGetVlbCoefs(var);
12496  vbdconsts = SCIPvarGetVlbConstants(var);
12497  nvbdvars = SCIPvarGetNVlbs(var);
12498 
12499  for( b = 0; b < nvbdvars; ++b )
12500  {
12501  if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12502  {
12503  if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12504  {
12505  for( j = 0; j < nvars; ++j )
12506  {
12507  if( vars[j] == vbdvars[b] )
12508  break;
12509  }
12510  if( j == nvars )
12511  continue;
12512 
12513  if( demands[i] + demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12514  {
12515  SCIP_Bool infeasible;
12516  char name[SCIP_MAXSTRLEN];
12517  int nlocalbdchgs;
12518 
12519  SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12520 
12521  /* construct constraint name */
12522  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12523 
12524  SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12525  nconss++;
12526 
12527  SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12528  assert(!infeasible);
12529 
12530  (*nchgbds) += nlocalbdchgs;
12531  }
12532  }
12533  }
12534  }
12535  }
12536 
12537  (*naddconss) += nconss;
12538 
12539  consdata->varbounds = TRUE;
12540 
12541  return SCIP_OKAY;
12542 }
12543 
12544 /** helper function to enforce constraints */
12545 static
12547  SCIP* scip, /**< SCIP data structure */
12548  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
12549  SCIP_CONS** conss, /**< constraints to process */
12550  int nconss, /**< number of constraints */
12551  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
12552  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
12553  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
12554  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
12555  )
12556 {
12557  SCIP_CONSHDLRDATA* conshdlrdata;
12558 
12559  assert(conshdlr != NULL);
12560  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12561  assert(nconss == 0 || conss != NULL);
12562  assert(result != NULL);
12563 
12564  if( solinfeasible )
12565  {
12566  *result = SCIP_INFEASIBLE;
12567  return SCIP_OKAY;
12568  }
12569 
12570  SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12571  sol == NULL ? "LP" : "relaxation");
12572 
12573  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12574  assert(conshdlrdata != NULL);
12575 
12576  (*result) = SCIP_FEASIBLE;
12577 
12578  if( conshdlrdata->usebinvars )
12579  {
12580  SCIP_Bool separated;
12581  SCIP_Bool cutoff;
12582  int c;
12583 
12584  separated = FALSE;
12585 
12586  /* first check if a constraints is violated */
12587  for( c = 0; c < nusefulconss; ++c )
12588  {
12589  SCIP_CONS* cons;
12590  SCIP_Bool violated;
12591 
12592  cons = conss[c];
12593  assert(cons != NULL);
12594 
12595  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12596 
12597  if( !violated )
12598  continue;
12599 
12600  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12601  if ( cutoff )
12602  {
12603  *result = SCIP_CUTOFF;
12604  return SCIP_OKAY;
12605  }
12606  }
12607 
12608  for( ; c < nconss && !separated; ++c )
12609  {
12610  SCIP_CONS* cons;
12611  SCIP_Bool violated;
12612 
12613  cons = conss[c];
12614  assert(cons != NULL);
12615 
12616  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12617 
12618  if( !violated )
12619  continue;
12620 
12621  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12622  if ( cutoff )
12623  {
12624  *result = SCIP_CUTOFF;
12625  return SCIP_OKAY;
12626  }
12627  }
12628 
12629  if( separated )
12630  (*result) = SCIP_SEPARATED;
12631  }
12632  else
12633  {
12634  SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12635  }
12636 
12637  return SCIP_OKAY;
12638 }
12639 
12640 /**@} */
12641 
12642 
12643 /**@name Callback methods of constraint handler
12644  *
12645  * @{
12646  */
12647 
12648 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12649 static
12650 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12651 { /*lint --e{715}*/
12652  assert(scip != NULL);
12653  assert(conshdlr != NULL);
12654  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12655 
12656  /* call inclusion method of constraint handler */
12658 
12660 
12661  *valid = TRUE;
12662 
12663  return SCIP_OKAY;
12664 }
12665 
12666 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12667 static
12668 SCIP_DECL_CONSFREE(consFreeCumulative)
12669 { /*lint --e{715}*/
12670  SCIP_CONSHDLRDATA* conshdlrdata;
12671 
12672  assert(conshdlr != NULL);
12673  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12674 
12675  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12676  assert(conshdlrdata != NULL);
12677 
12678 #ifdef SCIP_STATISTIC
12679  if( !conshdlrdata->iscopy )
12680  {
12681  /* statisitc output if SCIP_STATISTIC is defined */
12682  SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12683  conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12684  SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12685  conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12686  SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12687  conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12688  }
12689 #endif
12690 
12691  conshdlrdataFree(scip, &conshdlrdata);
12692 
12693  SCIPconshdlrSetData(conshdlr, NULL);
12694 
12695  return SCIP_OKAY;
12696 }
12697 
12698 
12699 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12700 static
12701 SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12702 { /*lint --e{715}*/
12703  SCIP_CONSHDLRDATA* conshdlrdata;
12704  int c;
12705 
12706  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12707  assert(conshdlrdata != NULL);
12708 
12709  conshdlrdata->detectedredundant = FALSE;
12710 
12711  for( c = 0; c < nconss; ++c )
12712  {
12713  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12714  * hmax)
12715  */
12716  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12717  }
12718 
12719  return SCIP_OKAY;
12720 }
12721 
12722 
12723 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12724 #ifdef SCIP_STATISTIC
12725 static
12726 SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12727 { /*lint --e{715}*/
12728  SCIP_CONSHDLRDATA* conshdlrdata;
12729  int c;
12730 
12731  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12732  assert(conshdlrdata != NULL);
12733 
12734  for( c = 0; c < nconss; ++c )
12735  {
12736  SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12737 
12738 #if 0
12739  SCIP_CALL( SCIPvisualizeConsCumulative(scip, conss[c]) );
12740 #endif
12741  }
12742 
12743  if( !conshdlrdata->iscopy )
12744  {
12745  SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12746  SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12747  SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12748  SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12749  SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12750  SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12751  SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12752  SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12753  SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12754  }
12755 
12756  return SCIP_OKAY;
12757 }
12758 #endif
12759 
12760 
12761 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12762 static
12763 SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12764 { /*lint --e{715}*/
12765  SCIP_CONSDATA* consdata;
12766  int c;
12767 
12768  assert(conshdlr != NULL);
12769  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12770 
12771  /* release the rows of all constraints */
12772  for( c = 0; c < nconss; ++c )
12773  {
12774  consdata = SCIPconsGetData(conss[c]);
12775  assert(consdata != NULL);
12776 
12777  /* free rows */
12778  SCIP_CALL( consdataFreeRows(scip, &consdata) );
12779  }
12780 
12781  return SCIP_OKAY;
12782 }
12783 
12784 /** frees specific constraint data */
12785 static
12786 SCIP_DECL_CONSDELETE(consDeleteCumulative)
12787 { /*lint --e{715}*/
12788  assert(conshdlr != NULL);
12789  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12790  assert(consdata != NULL );
12791  assert(*consdata != NULL );
12792 
12793  /* if constraint belongs to transformed problem space, drop bound change events on variables */
12794  if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12795  {
12796  SCIP_CONSHDLRDATA* conshdlrdata;
12797 
12798  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12799  assert(conshdlrdata != NULL);
12800 
12801  SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12802  }
12803 
12804  /* free cumulative constraint data */
12805  SCIP_CALL( consdataFree(scip, consdata) );
12806 
12807  return SCIP_OKAY;
12808 }
12809 
12810 /** transforms constraint data into data belonging to the transformed problem */
12811 static
12812 SCIP_DECL_CONSTRANS(consTransCumulative)
12813 { /*lint --e{715}*/
12814  SCIP_CONSHDLRDATA* conshdlrdata;
12815  SCIP_CONSDATA* sourcedata;
12816  SCIP_CONSDATA* targetdata;
12817 
12818  assert(conshdlr != NULL);
12819  assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
12820  assert(sourcecons != NULL);
12821  assert(targetcons != NULL);
12822 
12823  sourcedata = SCIPconsGetData(sourcecons);
12824  assert(sourcedata != NULL);
12825  assert(sourcedata->demandrows == NULL);
12826 
12827  SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12828 
12829  /* get event handler */
12830  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12831  assert(conshdlrdata != NULL);
12832  assert(conshdlrdata->eventhdlr != NULL);
12833 
12834  /* create constraint data for target constraint */
12835  SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12836  sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12837  sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12838 
12839  /* create target constraint */
12840  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12841  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12842  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12843  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12844  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12845 
12846  /* catch bound change events of variables */
12847  SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12848 
12849  return SCIP_OKAY;
12850 }
12851 
12852 /** LP initialization method of constraint handler */
12853 static
12854 SCIP_DECL_CONSINITLP(consInitlpCumulative)
12856  SCIP_CONSHDLRDATA* conshdlrdata;
12857  int c;
12858 
12859  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12860  assert(conshdlr != NULL);
12861  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12862  assert(conshdlrdata != NULL);
12863 
12864  *infeasible = FALSE;
12865 
12866  SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12867 
12868  if( conshdlrdata->usebinvars )
12869  {
12870  /* add rows to LP */
12871  for( c = 0; c < nconss && !(*infeasible); ++c )
12872  {
12873  assert(SCIPconsIsInitial(conss[c]));
12874  SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12875 
12876  if( conshdlrdata->cutsasconss )
12877  {
12878  SCIP_CALL( SCIPrestartSolve(scip) );
12879  }
12880  }
12881  }
12882 
12883  /**@todo if we want to use only the integer variables; only these will be in cuts
12884  * create some initial cuts, currently these are only separated */
12885 
12886  return SCIP_OKAY;
12887 }
12888 
12889 /** separation method of constraint handler for LP solutions */
12890 static
12891 SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12893  SCIP_CONSHDLRDATA* conshdlrdata;
12894  SCIP_Bool cutoff;
12895  SCIP_Bool separated;
12896  int c;
12897 
12898  SCIPdebugMsg(scip, "consSepalpCumulative\n");
12899 
12900  assert(conshdlr != NULL);
12901  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12902  assert(nconss == 0 || conss != NULL);
12903  assert(result != NULL);
12904  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12905  assert(conshdlrdata != NULL);
12906 
12907  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12908 
12909  cutoff = FALSE;
12910  separated = FALSE;
12911  (*result) = SCIP_DIDNOTRUN;
12912 
12913  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12914  return SCIP_OKAY;
12915 
12916  (*result) = SCIP_DIDNOTFIND;
12917 
12918  if( conshdlrdata->usebinvars )
12919  {
12920  /* check all useful cumulative constraints for feasibility */
12921  for( c = 0; c < nusefulconss && !cutoff; ++c )
12922  {
12923  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12924  }
12925 
12926  if( !cutoff && conshdlrdata->usecovercuts )
12927  {
12928  for( c = 0; c < nusefulconss; ++c )
12929  {
12930  SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12931  }
12932  }
12933  }
12934 
12935  if( conshdlrdata->sepaold )
12936  {
12937  /* separate cuts containing only integer variables */
12938  for( c = 0; c < nusefulconss; ++c )
12939  {
12940  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12941  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12942  }
12943  }
12944 
12945  if( cutoff )
12946  *result = SCIP_CUTOFF;
12947  else if( separated )
12948  *result = SCIP_SEPARATED;
12949 
12950  return SCIP_OKAY;
12951 }
12952 
12953 /** separation method of constraint handler for arbitrary primal solutions */
12954 static
12955 SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12956 { /*lint --e{715}*/
12957  SCIP_CONSHDLRDATA* conshdlrdata;
12958  SCIP_Bool cutoff;
12959  SCIP_Bool separated;
12960  int c;
12961 
12962  assert(conshdlr != NULL);
12963  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12964  assert(nconss == 0 || conss != NULL);
12965  assert(result != NULL);
12966 
12967  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12968  assert(conshdlrdata != NULL);
12969 
12970  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12971  return SCIP_OKAY;
12972 
12973  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12974 
12975  cutoff = FALSE;
12976  separated = FALSE;
12977  (*result) = SCIP_DIDNOTFIND;
12978 
12979  if( conshdlrdata->usebinvars )
12980  {
12981  /* check all useful cumulative constraints for feasibility */
12982  for( c = 0; c < nusefulconss && !cutoff; ++c )
12983  {
12984  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12985  }
12986 
12987  if( !cutoff && conshdlrdata->usecovercuts )
12988  {
12989  for( c = 0; c < nusefulconss; ++c )
12990  {
12991  SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12992  }
12993  }
12994  }
12995  if( conshdlrdata->sepaold )
12996  {
12997  /* separate cuts containing only integer variables */
12998  for( c = 0; c < nusefulconss; ++c )
12999  {
13000  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
13001  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
13002  }
13003  }
13004 
13005  if( cutoff )
13006  *result = SCIP_CUTOFF;
13007  else if( separated )
13008  *result = SCIP_SEPARATED;
13009 
13010  return SCIP_OKAY;
13011 }
13012 
13013 /** constraint enforcing method of constraint handler for LP solutions */
13014 static
13015 SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
13016 { /*lint --e{715}*/
13017  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
13018 
13019  return SCIP_OKAY;
13020 }
13021 
13022 /** constraint enforcing method of constraint handler for relaxation solutions */
13023 static
13024 SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
13025 { /*lint --e{715}*/
13026  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
13027 
13028  return SCIP_OKAY;
13029 }
13030 
13031 /** constraint enforcing method of constraint handler for pseudo solutions */
13032 static
13033 SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
13034 { /*lint --e{715}*/
13035  SCIP_CONSHDLRDATA* conshdlrdata;
13036 
13037  SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
13038 
13039  assert(conshdlr != NULL);
13040  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13041  assert(nconss == 0 || conss != NULL);
13042  assert(result != NULL);
13043 
13044  if( objinfeasible )
13045  {
13046  *result = SCIP_DIDNOTRUN;
13047  return SCIP_OKAY;
13048  }
13049 
13050  (*result) = SCIP_FEASIBLE;
13051 
13052  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13053  assert(conshdlrdata != NULL);
13054 
13055  SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
13056 
13057  return SCIP_OKAY;
13058 }
13059 
13060 /** feasibility check method of constraint handler for integral solutions */
13061 static
13062 SCIP_DECL_CONSCHECK(consCheckCumulative)
13063 { /*lint --e{715}*/
13064  int c;
13065 
13066  assert(conshdlr != NULL);
13067  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13068  assert(nconss == 0 || conss != NULL);
13069  assert(result != NULL);
13070 
13071  *result = SCIP_FEASIBLE;
13072 
13073  SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
13074 
13075  for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
13076  {
13077  SCIP_Bool violated = FALSE;
13078 
13079  SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
13080 
13081  if( violated )
13082  *result = SCIP_INFEASIBLE;
13083  }
13084 
13085  return SCIP_OKAY;
13086 }
13087 
13088 /** domain propagation method of constraint handler */
13089 static
13090 SCIP_DECL_CONSPROP(consPropCumulative)
13091 { /*lint --e{715}*/
13092  SCIP_CONSHDLRDATA* conshdlrdata;
13093  SCIP_Bool cutoff;
13094  int nchgbds;
13095  int ndelconss;
13096  int c;
13097 #if 0
13098  int naggrvars = 0;
13099 #endif
13100 
13101  SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
13102 
13103  assert(conshdlr != NULL);
13104  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13105  assert(nconss == 0 || conss != NULL);
13106  assert(result != NULL);
13107 
13108  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13109  assert(conshdlrdata != NULL);
13110 
13111  nchgbds = 0;
13112  ndelconss = 0;
13113  cutoff = FALSE;
13114  (*result) = SCIP_DIDNOTRUN;
13115 
13116  /* propgate all useful constraints */
13117  for( c = 0; c < nusefulconss && !cutoff; ++c )
13118  {
13119  SCIP_CONS* cons;
13120 
13121  cons = conss[c];
13122  assert(cons != NULL);
13123 
13124  if( SCIPgetDepth(scip) == 0 )
13125  {
13126 #if 0
13127  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13128  &nchgbds, &naggrvars, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13129 #else
13130  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13131  &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13132 #endif
13133  if( cutoff )
13134  break;
13135 
13136  if( SCIPconsIsDeleted(cons) )
13137  continue;
13138  }
13139 
13140  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13141  }
13142 
13143  if( !cutoff && nchgbds == 0 )
13144  {
13145  /* propgate all other constraints */
13146  for( c = nusefulconss; c < nconss && !cutoff; ++c )
13147  {
13148  SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13149  }
13150  }
13151 
13152 #if 0
13153  if( !cutoff && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 )
13154  {
13155  SCIP_CALL( propagateAllConss(scip, conss, nconss, TRUE, &nchgbds, &cutoff, NULL) );
13156  }
13157 #endif
13158 
13159  if( cutoff )
13160  {
13161  SCIPdebugMsg(scip, "detected infeasible\n");
13162  *result = SCIP_CUTOFF;
13163  }
13164  else if( nchgbds > 0 )
13165  {
13166  SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13167  *result = SCIP_REDUCEDDOM;
13168  }
13169  else
13170  *result = SCIP_DIDNOTFIND;
13171 
13172  return SCIP_OKAY;
13173 }
13174 
13175 /** presolving method of constraint handler */
13176 static
13177 SCIP_DECL_CONSPRESOL(consPresolCumulative)
13178 { /*lint --e{715}*/
13179  SCIP_CONSHDLRDATA* conshdlrdata;
13180  SCIP_CONS* cons;
13181  SCIP_Bool cutoff;
13182  SCIP_Bool unbounded;
13183  int oldnfixedvars;
13184  int oldnchgbds;
13185  int oldndelconss;
13186  int oldnaddconss;
13187  int oldnupgdconss;
13188  int oldnchgsides;
13189  int oldnchgcoefs;
13190  int c;
13191 
13192  assert(conshdlr != NULL);
13193  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13194  assert(scip != NULL);
13195  assert(result != NULL);
13196 
13197  SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13198 
13199  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13200  assert(conshdlrdata != NULL);
13201 
13202  *result = SCIP_DIDNOTRUN;
13203 
13204  oldnfixedvars = *nfixedvars;
13205  oldnchgbds = *nchgbds;
13206  oldnchgsides = *nchgsides;
13207  oldnchgcoefs = *nchgcoefs;
13208  oldnupgdconss = *nupgdconss;
13209  oldndelconss = *ndelconss;
13210  oldnaddconss = *naddconss;
13211  cutoff = FALSE;
13212  unbounded = FALSE;
13213 
13214  /* process constraints */
13215  for( c = 0; c < nconss && !cutoff; ++c )
13216  {
13217  cons = conss[c];
13218 
13219  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13220  * hmax)
13221  */
13222  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13223 
13224  if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13225  {
13226 #if 0
13227  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13228  nfixedvars, naggrvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13229 #else
13230  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13231  nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13232 #endif
13233 
13234  if( cutoff || unbounded )
13235  break;
13236 
13237  if( SCIPconsIsDeleted(cons) )
13238  continue;
13239  }
13240 
13241  /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13242  if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13243  {
13244  SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13245  }
13246 
13247  /* strengthen existing variable bounds using the cumulative condition */
13248  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13249  {
13250  SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13251  }
13252 
13253  /* propagate cumulative constraint */
13254  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13255  assert(checkDemands(scip, cons) || cutoff);
13256  }
13257 
13258  if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13259  {
13260  SCIP_CALL( propagateAllConss(scip, conss, nconss, FALSE, nfixedvars, &cutoff, NULL) );
13261  }
13262 
13263  /* only perform the detection of variable bounds and disjunctive constraint once */
13264  if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13265  && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13266  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13267  {
13268  /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13269  * propagation
13270  */
13271  SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13272  conshdlrdata->detectedredundant = TRUE;
13273  }
13274 
13275  if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13276  {
13277  SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13278  }
13279 
13280  SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13281  *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13282 
13283  if( cutoff )
13284  *result = SCIP_CUTOFF;
13285  else if( unbounded )
13286  *result = SCIP_UNBOUNDED;
13287  else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13288  || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13289  *result = SCIP_SUCCESS;
13290  else
13291  *result = SCIP_DIDNOTFIND;
13292 
13293  return SCIP_OKAY;
13294 }
13295 
13296 /** propagation conflict resolving method of constraint handler */
13297 static
13298 SCIP_DECL_CONSRESPROP(consRespropCumulative)
13299 { /*lint --e{715}*/
13300  SCIP_CONSHDLRDATA* conshdlrdata;
13301  SCIP_CONSDATA* consdata;
13302 
13303  assert(conshdlr != NULL);
13304  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13305  assert(scip != NULL);
13306  assert(result != NULL);
13307  assert(infervar != NULL);
13308  assert(bdchgidx != NULL);
13309 
13310  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13311  assert(conshdlrdata != NULL);
13312 
13313  /* process constraint */
13314  assert(cons != NULL);
13315 
13316  consdata = SCIPconsGetData(cons);
13317  assert(consdata != NULL);
13318 
13319  SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13320  SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13321  SCIPgetHminCumulative(scip, cons), SCIPgetHmaxCumulative(scip, cons));
13322 
13323  SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13324  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13325  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13326 
13327  return SCIP_OKAY;
13328 }
13329 
13330 /** variable rounding lock method of constraint handler */
13331 static
13332 SCIP_DECL_CONSLOCK(consLockCumulative)
13333 { /*lint --e{715}*/
13334  SCIP_CONSDATA* consdata;
13335  SCIP_VAR** vars;
13336  int v;
13337 
13338  SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13339 
13340  assert(scip != NULL);
13341  assert(cons != NULL);
13342  assert(locktype == SCIP_LOCKTYPE_MODEL);
13343 
13344  consdata = SCIPconsGetData(cons);
13345  assert(consdata != NULL);
13346 
13347  vars = consdata->vars;
13348  assert(vars != NULL);
13349 
13350  for( v = 0; v < consdata->nvars; ++v )
13351  {
13352  if( consdata->downlocks[v] && consdata->uplocks[v] )
13353  {
13354  /* the integer start variable should not get rounded in both direction */
13355  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
13356  }
13357  else if( consdata->downlocks[v] )
13358  {
13359  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
13360  }
13361  else if( consdata->uplocks[v] )
13362  {
13363  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
13364  }
13365  }
13366 
13367  return SCIP_OKAY;
13368 }
13369 
13370 
13371 /** constraint display method of constraint handler */
13372 static
13373 SCIP_DECL_CONSPRINT(consPrintCumulative)
13374 { /*lint --e{715}*/
13375  assert(scip != NULL);
13376  assert(conshdlr != NULL);
13377  assert(cons != NULL);
13378 
13379  consdataPrint(scip, SCIPconsGetData(cons), file);
13380 
13381  return SCIP_OKAY;
13382 }
13383 
13384 /** constraint copying method of constraint handler */
13385 static
13386 SCIP_DECL_CONSCOPY(consCopyCumulative)
13387 { /*lint --e{715}*/
13388  SCIP_CONSDATA* sourceconsdata;
13389  SCIP_VAR** sourcevars;
13390  SCIP_VAR** vars;
13391  const char* consname;
13392 
13393  int nvars;
13394  int v;
13395 
13396  sourceconsdata = SCIPconsGetData(sourcecons);
13397  assert(sourceconsdata != NULL);
13398 
13399  /* get variables of the source constraint */
13400  nvars = sourceconsdata->nvars;
13401  sourcevars = sourceconsdata->vars;
13402 
13403  (*valid) = TRUE;
13404 
13405  if( nvars == 0 )
13406  return SCIP_OKAY;
13407 
13408  /* allocate buffer array */
13409  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13410 
13411  for( v = 0; v < nvars && *valid; ++v )
13412  {
13413  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13414  assert(!(*valid) || vars[v] != NULL);
13415  }
13416 
13417  /* only create the target constraint, if all variables could be copied */
13418  if( *valid )
13419  {
13420  if( name != NULL )
13421  consname = name;
13422  else
13423  consname = SCIPconsGetName(sourcecons);
13424 
13425  /* create a copy of the cumulative constraint */
13426  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13427  sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13428  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13429 
13430  /* adjust left side if the time axis if needed */
13431  if( sourceconsdata->hmin > 0 )
13432  {
13433  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13434  }
13435 
13436  /* adjust right side if the time axis if needed */
13437  if( sourceconsdata->hmax < INT_MAX )
13438  {
13439  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13440  }
13441  }
13442 
13443  /* free buffer array */
13444  SCIPfreeBufferArray(scip, &vars);
13445 
13446  return SCIP_OKAY;
13447 }
13448 
13449 
13450 /** constraint parsing method of constraint handler */
13451 static
13452 SCIP_DECL_CONSPARSE(consParseCumulative)
13453 { /*lint --e{715}*/
13454  SCIP_VAR** vars;
13455  SCIP_VAR* var;
13456  SCIP_Real value;
13457  char strvalue[SCIP_MAXSTRLEN];
13458  char* endptr;
13459  int* demands;
13460  int* durations;
13461  int capacity;
13462  int duration;
13463  int demand;
13464  int hmin;
13465  int hmax;
13466  int varssize;
13467  int nvars;
13468 
13469  SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13470 
13471  *success = TRUE;
13472 
13473  /* cutoff "cumulative" form the constraint string */
13474  SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13475  str = endptr;
13476 
13477  varssize = 100;
13478  nvars = 0;
13479 
13480  /* allocate buffer array for variables */
13481  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13482  SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13483  SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13484 
13485  do
13486  {
13487  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13488 
13489  if( var == NULL )
13490  {
13491  endptr = strchr(endptr, ')');
13492 
13493  if( endptr == NULL )
13494  *success = FALSE;
13495  else
13496  str = endptr;
13497 
13498  break;
13499  }
13500 
13501  str = endptr;
13502  SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13503  duration = atoi(strvalue);
13504  str = endptr;
13505 
13506  SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13507  demand = atoi(strvalue);
13508  str = endptr;
13509 
13510  SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13511 
13512  vars[nvars] = var;
13513  demands[nvars] = demand;
13514  durations[nvars] = duration;
13515  nvars++;
13516  }
13517  while( *str != ')' );
13518 
13519  if( *success )
13520  {
13521  /* parse effective time window */
13522  SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13523  hmin = atoi(strvalue);
13524  str = endptr;
13525 
13526  if( SCIPparseReal(scip, str, &value, &endptr) )
13527  {
13528  hmax = (int)(value);
13529  str = endptr;
13530 
13531  /* parse capacity */
13532  SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13533  str = endptr;
13534  if( SCIPparseReal(scip, str, &value, &endptr) )
13535  {
13536  capacity = (int)value;
13537 
13538  /* create cumulative constraint */
13539  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13540  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13541 
13542  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13543  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13544  }
13545  }
13546  }
13547 
13548  /* free buffer arrays */
13549  SCIPfreeBufferArray(scip, &durations);
13550  SCIPfreeBufferArray(scip, &demands);
13551  SCIPfreeBufferArray(scip, &vars);
13552 
13553  return SCIP_OKAY;
13554 }
13555 
13556 
13557 /** constraint method of constraint handler which returns the variables (if possible) */
13558 static
13559 SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13560 { /*lint --e{715}*/
13561  SCIP_CONSDATA* consdata;
13562 
13563  consdata = SCIPconsGetData(cons);
13564  assert(consdata != NULL);
13565 
13566  if( varssize < consdata->nvars )
13567  (*success) = FALSE;
13568  else
13569  {
13570  assert(vars != NULL);
13571 
13572  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13573  (*success) = TRUE;
13574  }
13575 
13576  return SCIP_OKAY;
13577 }
13578 
13579 /** constraint method of constraint handler which returns the number of variables (if possible) */
13580 static
13581 SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13582 { /*lint --e{715}*/
13583  SCIP_CONSDATA* consdata;
13584 
13585  consdata = SCIPconsGetData(cons);
13586  assert(consdata != NULL);
13587 
13588  (*nvars) = consdata->nvars;
13589  (*success) = TRUE;
13590 
13591  return SCIP_OKAY;
13592 }
13593 
13594 /**@} */
13595 
13596 /**@name Callback methods of event handler
13597  *
13598  * @{
13599  */
13600 
13601 
13602 /** execution method of event handler */
13603 static
13604 SCIP_DECL_EVENTEXEC(eventExecCumulative)
13605 { /*lint --e{715}*/
13606  SCIP_CONSDATA* consdata;
13607 
13608  assert(scip != NULL);
13609  assert(eventhdlr != NULL);
13610  assert(eventdata != NULL);
13611  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13612  assert(event != NULL);
13613 
13614  consdata = (SCIP_CONSDATA*)eventdata;
13615  assert(consdata != NULL);
13616 
13617  /* mark the constraint to be not propagated */
13618  consdata->propagated = FALSE;
13619 
13620  return SCIP_OKAY;
13621 }
13622 
13623 /**@} */
13624 
13625 /*
13626  * constraint specific interface methods
13627  */
13628 
13629 /** creates the handler for cumulative constraints and includes it in SCIP */
13631  SCIP* scip /**< SCIP data structure */
13632  )
13633 {
13634  SCIP_CONSHDLRDATA* conshdlrdata;
13635  SCIP_CONSHDLR* conshdlr;
13636  SCIP_EVENTHDLR* eventhdlr;
13637 
13638  /* create event handler for bound change events */
13639  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13640 
13641  /* create cumulative constraint handler data */
13642  SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13643 
13644  /* include constraint handler */
13647  consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13648  conshdlrdata) );
13649 
13650  assert(conshdlr != NULL);
13651 
13652  /* set non-fundamental callbacks via specific setter functions */
13653  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13654  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13655 #ifdef SCIP_STATISTIC
13656  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13657 #endif
13658  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13659  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13660  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13661  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13662  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13663  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13664  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13665  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13667  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13668  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropCumulative, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13670  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13671  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13673  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13674  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
13675 
13676  /* add cumulative constraint handler parameters */
13678  "constraints/" CONSHDLR_NAME "/ttinfer",
13679  "should time-table (core-times) propagator be used to infer bounds?",
13680  &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13682  "constraints/" CONSHDLR_NAME "/efcheck",
13683  "should edge-finding be used to detect an overload?",
13684  &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13686  "constraints/" CONSHDLR_NAME "/efinfer",
13687  "should edge-finding be used to infer bounds?",
13688  &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13690  "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13691  &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13693  "constraints/" CONSHDLR_NAME "/ttefcheck",
13694  "should time-table edge-finding be used to detect an overload?",
13695  &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13697  "constraints/" CONSHDLR_NAME "/ttefinfer",
13698  "should time-table edge-finding be used to infer bounds?",
13699  &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13700 
13702  "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13703  &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13705  "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13706  &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13708  "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13709  &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13711  "constraints/" CONSHDLR_NAME "/cutsasconss",
13712  "should the cumulative constraint create cuts as knapsack constraints?",
13713  &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13715  "constraints/" CONSHDLR_NAME "/sepaold",
13716  "shall old sepa algo be applied?",
13717  &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13718 
13720  "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13721  &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13722 
13723  /* presolving parameters */
13725  "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13726  &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13728  "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13729  &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13731  "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13732  &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13734  "constraints/" CONSHDLR_NAME "/presolpairwise",
13735  "should pairwise constraint comparison be performed in presolving?",
13736  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13738  "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13739  &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13740 
13742  "constraints/" CONSHDLR_NAME "/maxnodes",
13743  "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13744  &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13746  "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13747  &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13749  "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13750  &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13751 
13752  /* conflict analysis parameters */
13754  "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13755  &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13756 
13757  return SCIP_OKAY;
13758 }
13759 
13760 /** creates and captures a cumulative constraint */
13762  SCIP* scip, /**< SCIP data structure */
13763  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13764  const char* name, /**< name of constraint */
13765  int nvars, /**< number of variables (jobs) */
13766  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13767  int* durations, /**< array containing corresponding durations */
13768  int* demands, /**< array containing corresponding demands */
13769  int capacity, /**< available cumulative capacity */
13770  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13771  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13772  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13773  * Usually set to TRUE. */
13774  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13775  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13776  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13777  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13778  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13779  * Usually set to TRUE. */
13780  SCIP_Bool local, /**< is constraint only valid locally?
13781  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13782  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13783  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13784  * adds coefficients to this constraint. */
13785  SCIP_Bool dynamic, /**< is constraint subject to aging?
13786  * Usually set to FALSE. Set to TRUE for own cuts which
13787  * are seperated as constraints. */
13788  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13789  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13790  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13791  * if it may be moved to a more global node?
13792  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13793  )
13794 {
13795  SCIP_CONSHDLR* conshdlr;
13796  SCIP_CONSDATA* consdata;
13797 
13798  assert(scip != NULL);
13799 
13800  /* find the cumulative constraint handler */
13801  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13802  if( conshdlr == NULL )
13803  {
13804  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13805  return SCIP_PLUGINNOTFOUND;
13806  }
13807 
13808  SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13809 
13810  /* create constraint data */
13811  SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13812 
13813  /* create constraint */
13814  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13815  initial, separate, enforce, check, propagate,
13816  local, modifiable, dynamic, removable, stickingatnode) );
13817 
13818  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13819  {
13820  SCIP_CONSHDLRDATA* conshdlrdata;
13821 
13822  /* get event handler */
13823  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13824  assert(conshdlrdata != NULL);
13825  assert(conshdlrdata->eventhdlr != NULL);
13826 
13827  /* catch bound change events of variables */
13828  SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13829  }
13830 
13831  return SCIP_OKAY;
13832 }
13833 
13834 /** creates and captures a cumulative constraint
13835  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13836  * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13837  *
13838  * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13839  *
13840  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13841  */
13843  SCIP* scip, /**< SCIP data structure */
13844  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13845  const char* name, /**< name of constraint */
13846  int nvars, /**< number of variables (jobs) */
13847  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13848  int* durations, /**< array containing corresponding durations */
13849  int* demands, /**< array containing corresponding demands */
13850  int capacity /**< available cumulative capacity */
13851  )
13852 {
13853  assert(scip != NULL);
13854 
13855  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13856  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13857 
13858  return SCIP_OKAY;
13859 }
13860 
13861 /** set the left bound of the time axis to be considered (including hmin) */ /*lint -e{715}*/
13863  SCIP* scip, /**< SCIP data structure */
13864  SCIP_CONS* cons, /**< constraint data */
13865  int hmin /**< left bound of time axis to be considered */
13866  )
13867 {
13868  SCIP_CONSDATA* consdata;
13869  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13870  {
13871  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13872  return SCIP_INVALIDCALL;
13873  }
13874 
13875  consdata = SCIPconsGetData(cons);
13876  assert(consdata != NULL);
13877  assert(hmin >= 0);
13878  assert(hmin <= consdata->hmax);
13879 
13880  consdata->hmin = hmin;
13881 
13882  return SCIP_OKAY;
13883 }
13884 
13885 /** returns the left bound of the time axis to be considered */ /*lint -e{715}*/
13887  SCIP* scip, /**< SCIP data structure */
13888  SCIP_CONS* cons /**< constraint */
13889  )
13890 {
13891  SCIP_CONSDATA* consdata;
13892  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13893  {
13894  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13895  SCIPABORT();
13896  return 0; /*lint !e527*/
13897  }
13898 
13899  consdata = SCIPconsGetData(cons);
13900  assert(consdata != NULL);
13901 
13902  return consdata->hmin;
13903 }
13904 
13905 /** set the right bound of the time axis to be considered (not including hmax) */ /*lint -e{715}*/
13907  SCIP* scip, /**< SCIP data structure */
13908  SCIP_CONS* cons, /**< constraint data */
13909  int hmax /**< right bound of time axis to be considered */
13910  )
13911 {
13912  SCIP_CONSDATA* consdata;
13913  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13914  {
13915  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13916  SCIPABORT();
13917  return SCIP_INVALIDCALL; /*lint !e527*/
13918  }
13919 
13920  consdata = SCIPconsGetData(cons);
13921  assert(consdata != NULL);
13922  assert(hmax >= consdata->hmin);
13923 
13924  consdata->hmax = hmax;
13925 
13926  return SCIP_OKAY;
13927 }
13928 
13929 /** returns the right bound of the time axis to be considered */ /*lint -e{715}*/
13931  SCIP* scip, /**< SCIP data structure */
13932  SCIP_CONS* cons /**< constraint */
13933  )
13934 {
13935  SCIP_CONSDATA* consdata;
13936  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13937  {
13938  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13939  SCIPABORT();
13940  return 0; /*lint !e527*/
13941  }
13942 
13943  consdata = SCIPconsGetData(cons);
13944  assert(consdata != NULL);
13945 
13946  return consdata->hmax;
13947 }
13948 
13949 /** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13951  SCIP* scip, /**< SCIP data structure */
13952  SCIP_CONS* cons /**< constraint data */
13953  )
13954 {
13955  SCIP_CONSDATA* consdata;
13956 
13957  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13958  {
13959  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13960  SCIPABORT();
13961  return NULL; /*lint !e527*/
13962  }
13963 
13964  consdata = SCIPconsGetData(cons);
13965  assert(consdata != NULL);
13966 
13967  return consdata->vars;
13968 }
13969 
13970 /** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13972  SCIP* scip, /**< SCIP data structure */
13973  SCIP_CONS* cons /**< constraint data */
13974  )
13975 {
13976  SCIP_CONSDATA* consdata;
13977 
13978  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13979  {
13980  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13981  SCIPABORT();
13982  return -1; /*lint !e527*/
13983  }
13984 
13985  consdata = SCIPconsGetData(cons);
13986  assert(consdata != NULL);
13987 
13988  return consdata->nvars;
13989 }
13990 
13991 /** returns the capacity of the cumulative constraint */ /*lint -e{715}*/
13993  SCIP* scip, /**< SCIP data structure */
13994  SCIP_CONS* cons /**< constraint data */
13995  )
13996 {
13997  SCIP_CONSDATA* consdata;
13998 
13999  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14000  {
14001  SCIPerrorMessage("constraint is not a cumulative constraint\n");
14002  SCIPABORT();
14003  return -1; /*lint !e527*/
14004  }
14005 
14006  consdata = SCIPconsGetData(cons);
14007  assert(consdata != NULL);
14008 
14009  return consdata->capacity;
14010 }
14011 
14012 /** returns the durations of the cumulative constraint */ /*lint -e{715}*/
14014  SCIP* scip, /**< SCIP data structure */
14015  SCIP_CONS* cons /**< constraint data */
14016  )
14017 {
14018  SCIP_CONSDATA* consdata;
14019 
14020  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14021  {
14022  SCIPerrorMessage("constraint is not a cumulative constraint\n");
14023  SCIPABORT();
14024  return NULL; /*lint !e527*/
14025  }
14026 
14027  consdata = SCIPconsGetData(cons);
14028  assert(consdata != NULL);
14029 
14030  return consdata->durations;
14031 }
14032 
14033 /** returns the demands of the cumulative constraint */ /*lint -e{715}*/
14035  SCIP* scip, /**< SCIP data structure */
14036  SCIP_CONS* cons /**< constraint data */
14037  )
14038 {
14039  SCIP_CONSDATA* consdata;
14040 
14041  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14042  {
14043  SCIPerrorMessage("constraint is not a cumulative constraint\n");
14044  SCIPABORT();
14045  return NULL; /*lint !e527*/
14046  }
14047 
14048  consdata = SCIPconsGetData(cons);
14049  assert(consdata != NULL);
14050 
14051  return consdata->demands;
14052 }
14053 
14054 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
14055  * given solution is satisfied
14056  */
14058  SCIP* scip, /**< SCIP data structure */
14059  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
14060  int nvars, /**< number of variables (jobs) */
14061  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14062  int* durations, /**< array containing corresponding durations */
14063  int* demands, /**< array containing corresponding demands */
14064  int capacity, /**< available cumulative capacity */
14065  int hmin, /**< left bound of time axis to be considered (including hmin) */
14066  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14067  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
14068  SCIP_CONS* cons, /**< constraint which is checked */
14069  SCIP_Bool printreason /**< should the reason for the violation be printed? */
14070  )
14071 {
14072  assert(scip != NULL);
14073  assert(violated != NULL);
14074 
14075  SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
14076  violated, cons, printreason) );
14077 
14078  return SCIP_OKAY;
14079 }
14080 
14081 /** normalize cumulative condition */ /*lint -e{715}*/
14083  SCIP* scip, /**< SCIP data structure */
14084  int nvars, /**< number of start time variables (activities) */
14085  SCIP_VAR** vars, /**< array of start time variables */
14086  int* durations, /**< array of durations */
14087  int* demands, /**< array of demands */
14088  int* capacity, /**< pointer to store the changed cumulative capacity */
14089  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
14090  int* nchgsides /**< pointer to count number of side changes */
14091  )
14092 { /*lint --e{715}*/
14093  normalizeCumulativeCondition(scip, nvars, demands, capacity, nchgcoefs, nchgsides);
14094 
14095  return SCIP_OKAY;
14096 }
14097 
14098 /** searches for a time point within the cumulative condition were the cumulative condition can be split */
14100  SCIP* scip, /**< SCIP data structure */
14101  int nvars, /**< number of variables (jobs) */
14102  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14103  int* durations, /**< array containing corresponding durations */
14104  int* demands, /**< array containing corresponding demands */
14105  int capacity, /**< available cumulative capacity */
14106  int* hmin, /**< pointer to store the left bound of the effective horizon */
14107  int* hmax, /**< pointer to store the right bound of the effective horizon */
14108  int* split /**< point were the cumulative condition can be split */
14109  )
14110 {
14111  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14112  hmin, hmax, split) );
14113 
14114  return SCIP_OKAY;
14115 }
14116 
14117 /** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
14119  SCIP* scip, /**< SCIP data structure */
14120  int nvars, /**< number of start time variables (activities) */
14121  SCIP_VAR** vars, /**< array of start time variables */
14122  int* durations, /**< array of durations */
14123  int hmin, /**< left bound of time axis to be considered */
14124  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14125  SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
14126  SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
14127  SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
14128  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
14129  int* nfixedvars, /**< pointer to store the number of fixed variables */
14130  int* nchgsides, /**< pointer to store the number of changed sides */
14131  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
14132  )
14133 {
14134  if( nvars <= 1 )
14135  return SCIP_OKAY;
14136 
14137  /* presolve constraint form the earlier start time point of view */
14138  SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14139  irrelevants, nfixedvars, nchgsides, cutoff) );
14140 
14141  /* presolve constraint form the latest completion time point of view */
14142  SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14143  irrelevants, nfixedvars, nchgsides, cutoff) );
14144 
14145  return SCIP_OKAY;
14146 }
14147 
14148 /** propagate the given cumulative condition */
14150  SCIP* scip, /**< SCIP data structure */
14151  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
14152  int nvars, /**< number of variables (jobs) */
14153  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14154  int* durations, /**< array containing corresponding durations */
14155  int* demands, /**< array containing corresponding demands */
14156  int capacity, /**< available cumulative capacity */
14157  int hmin, /**< left bound of time axis to be considered (including hmin) */
14158  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14159  SCIP_CONS* cons, /**< constraint which gets propagated */
14160  int* nchgbds, /**< pointer to store the number of variable bound changes */
14161  SCIP_Bool* initialized, /**< was conflict analysis initialized */
14162  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14163  SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14164  )
14165 {
14166  SCIP_CONSHDLR* conshdlr;
14167  SCIP_CONSHDLRDATA* conshdlrdata;
14168  SCIP_Bool redundant;
14169 
14170  assert(scip != NULL);
14171  assert(cons != NULL);
14172  assert(initialized != NULL);
14173  assert(*initialized == FALSE);
14174  assert(cutoff != NULL);
14175  assert(*cutoff == FALSE);
14176 
14177  /* find the cumulative constraint handler */
14178  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14179  if( conshdlr == NULL )
14180  {
14181  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14182  return SCIP_PLUGINNOTFOUND;
14183  }
14184 
14185  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14186  assert(conshdlrdata != NULL);
14187 
14188  redundant = FALSE;
14189 
14190  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14191  nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14192  nchgbds, &redundant, initialized, explanation, cutoff) );
14193 
14194  return SCIP_OKAY;
14195 }
14196 
14197 /** resolve propagation w.r.t. the cumulative condition */
14199  SCIP* scip, /**< SCIP data structure */
14200  int nvars, /**< number of start time variables (activities) */
14201  SCIP_VAR** vars, /**< array of start time variables */
14202  int* durations, /**< array of durations */
14203  int* demands, /**< array of demands */
14204  int capacity, /**< cumulative capacity */
14205  int hmin, /**< left bound of time axis to be considered (including hmin) */
14206  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14207  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14208  int inferinfo, /**< the user information */
14209  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14210  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14211  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14212  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14213  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14214  )
14215 {
14216  SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14217  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14218 
14219  return SCIP_OKAY;
14220 }
14221 
14222 /** this method visualizes the cumulative structure in GML format */
14224  SCIP* scip, /**< SCIP data structure */
14225  SCIP_CONS* cons /**< cumulative constraint */
14226  )
14227 {
14228  SCIP_CONSDATA* consdata;
14229  SCIP_HASHTABLE* vars;
14230  FILE* file;
14231  SCIP_VAR* var;
14232  char filename[SCIP_MAXSTRLEN];
14233  int nvars;
14234  int v;
14235 
14236  SCIP_RETCODE retcode = SCIP_OKAY;
14237 
14238  /* open file */
14239  (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14240  file = fopen(filename, "w");
14241 
14242  /* check if the file was open */
14243  if( file == NULL )
14244  {
14245  SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14246  SCIPprintSysError(filename);
14247  return SCIP_FILECREATEERROR;
14248  }
14249 
14250  consdata = SCIPconsGetData(cons);
14251  assert(consdata != NULL);
14252 
14253  nvars = consdata->nvars;
14254 
14255  SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
14256  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
14257 
14258  /* create opening of the GML format */
14259  SCIPgmlWriteOpening(file, TRUE);
14260 
14261  for( v = 0; v < nvars; ++v )
14262  {
14263  char color[SCIP_MAXSTRLEN];
14264 
14265  var = consdata->vars[v];
14266  assert(var != NULL);
14267 
14268  SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
14269 
14270  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14271  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14272  else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14273  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14274  else
14275  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14276 
14277  SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14278  }
14279 
14280  for( v = 0; v < nvars; ++v )
14281  {
14282  SCIP_VAR** vbdvars;
14283  int nvbdvars;
14284  int b;
14285 
14286  var = consdata->vars[v];
14287  assert(var != NULL);
14288 
14289  vbdvars = SCIPvarGetVlbVars(var);
14290  nvbdvars = SCIPvarGetNVlbs(var);
14291 
14292  for( b = 0; b < nvbdvars; ++b )
14293  {
14294  if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14295  {
14296  SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14297  }
14298  }
14299 
14300 #if 0
14301  vbdvars = SCIPvarGetVubVars(var);
14302  nvbdvars = SCIPvarGetNVubs(var);
14303 
14304  for( b = 0; b < nvbdvars; ++b )
14305  {
14306  if( SCIPhashtableExists(vars, vbdvars[b]) )
14307  {
14308  SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14309  }
14310  }
14311 #endif
14312  }
14313 
14314  /* create closing of the GML format */
14315  SCIPgmlWriteClosing(file);
14316 TERMINATE:
14317  /* close file */
14318  fclose(file);
14319 
14320  SCIPhashtableFree(&vars);
14321 
14322  return retcode;
14323 }
14324 
14325 /** sets method to solve an individual cumulative condition */
14327  SCIP* scip, /**< SCIP data structure */
14328  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14329  )
14330 {
14331  SCIP_CONSHDLR* conshdlr;
14332  SCIP_CONSHDLRDATA* conshdlrdata;
14333 
14334  /* find the cumulative constraint handler */
14335  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14336  if( conshdlr == NULL )
14337  {
14338  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14339  return SCIP_PLUGINNOTFOUND;
14340  }
14341 
14342  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14343  assert(conshdlrdata != NULL);
14344 
14345  conshdlrdata->solveCumulative = solveCumulative;
14346 
14347  return SCIP_OKAY;
14348 }
14349 
14350 /** solves given cumulative condition as independent sub problem
14351  *
14352  * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14353  * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14354  * solver was interrupted.
14355  */
14357  SCIP* scip, /**< SCIP data structure */
14358  int njobs, /**< number of jobs (activities) */
14359  SCIP_Real* ests, /**< array with the earlier start time for each job */
14360  SCIP_Real* lsts, /**< array with the latest start time for each job */
14361  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14362  int* durations, /**< array of durations */
14363  int* demands, /**< array of demands */
14364  int capacity, /**< cumulative capacity */
14365  int hmin, /**< left bound of time axis to be considered (including hmin) */
14366  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14367  SCIP_Real timelimit, /**< time limit for solving in seconds */
14368  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14369  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14370  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14371  SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14372  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14373  SCIP_Bool* error /**< pointer to store if an error occurred */
14374  )
14375 {
14376  SCIP_CONSHDLR* conshdlr;
14377  SCIP_CONSHDLRDATA* conshdlrdata;
14378 
14379  (*solved) = TRUE;
14380  (*infeasible) = FALSE;
14381  (*unbounded) = FALSE;
14382  (*error) = FALSE;
14383 
14384  if( njobs == 0 )
14385  return SCIP_OKAY;
14386 
14387  /* find the cumulative constraint handler */
14388  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14389  if( conshdlr == NULL )
14390  {
14391  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14392  (*error) = TRUE;
14393  return SCIP_PLUGINNOTFOUND;
14394  }
14395 
14396  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14397  assert(conshdlrdata != NULL);
14398 
14399  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14400  if( timelimit > 0.0 && memorylimit > 10 )
14401  {
14402  SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14403  hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14404  }
14405 
14406  return SCIP_OKAY;
14407 }
14408 
14409 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14410  * completion time
14411  */
14413  SCIP* scip, /**< SCIP data structure */
14414  SCIP_PROFILE* profile, /**< resource profile */
14415  int nvars, /**< number of variables (jobs) */
14416  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14417  int* durations, /**< array containing corresponding durations */
14418  int* demands /**< array containing corresponding demands */
14419  )
14420 {
14421  SCIP_VAR* var;
14422  SCIP_HASHMAP* addedvars;
14423  int* copydemands;
14424  int* perm;
14425  int duration;
14426  int impliedest;
14427  int est;
14428  int impliedlct;
14429  int lct;
14430  int v;
14431 
14432  /* create hash map for variables which are added, mapping to their duration */
14433  SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
14434 
14435  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14436  SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14437 
14438  /* sort variables w.r.t. job demands */
14439  for( v = 0; v < nvars; ++v )
14440  {
14441  copydemands[v] = demands[v];
14442  perm[v] = v;
14443  }
14444  SCIPsortDownIntInt(copydemands, perm, nvars);
14445 
14446  /* add each job with its earliest start and latest completion time into the resource profile */
14447  for( v = 0; v < nvars; ++v )
14448  {
14449  int idx;
14450 
14451  idx = perm[v];
14452  assert(idx >= 0 && idx < nvars);
14453 
14454  var = vars[idx];
14455  assert(var != NULL);
14456 
14457  duration = durations[idx];
14458  assert(duration > 0);
14459 
14460  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
14461  SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14462 
14463  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14464  SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14465 
14466  if( impliedest < impliedlct )
14467  {
14468  SCIP_Bool infeasible;
14469  int pos;
14470 
14471  SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14472  assert(!infeasible);
14473  assert(pos == -1);
14474  }
14475 
14476  if( est == impliedest && lct == impliedlct )
14477  {
14478  SCIP_CALL( SCIPhashmapInsertInt(addedvars, (void*)var, duration) );
14479  }
14480  }
14481 
14482  SCIPfreeBufferArray(scip, &copydemands);
14483  SCIPfreeBufferArray(scip, &perm);
14484 
14485  SCIPhashmapFree(&addedvars);
14486 
14487  return SCIP_OKAY;
14488 }
14489 
14490 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */ /*lint -e{715}*/
14491 int SCIPcomputeHmin(
14492  SCIP* scip, /**< SCIP data structure */
14493  SCIP_PROFILE* profile, /**< worst case resource profile */
14494  int capacity /**< capacity to check */
14495  )
14496 {
14497  int* timepoints;
14498  int* loads;
14499  int ntimepoints;
14500  int t;
14501 
14502  ntimepoints = SCIPprofileGetNTimepoints(profile);
14503  timepoints = SCIPprofileGetTimepoints(profile);
14504  loads = SCIPprofileGetLoads(profile);
14505 
14506  /* find first time point which potentially violates the capacity restriction */
14507  for( t = 0; t < ntimepoints - 1; ++t )
14508  {
14509  /* check if the time point exceed w.r.t. worst case profile the capacity */
14510  if( loads[t] > capacity )
14511  {
14512  assert(t == 0 || loads[t-1] <= capacity);
14513  return timepoints[t];
14514  }
14515  }
14516 
14517  return INT_MAX;
14518 }
14519 
14520 /** 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}*/
14521 int SCIPcomputeHmax(
14522  SCIP* scip, /**< SCIP data structure */
14523  SCIP_PROFILE* profile, /**< worst case profile */
14524  int capacity /**< capacity to check */
14525  )
14526 {
14527  int* timepoints;
14528  int* loads;
14529  int ntimepoints;
14530  int t;
14531 
14532  ntimepoints = SCIPprofileGetNTimepoints(profile);
14533  timepoints = SCIPprofileGetTimepoints(profile);
14534  loads = SCIPprofileGetLoads(profile);
14535 
14536  /* find last time point which potentially violates the capacity restriction */
14537  for( t = ntimepoints - 1; t >= 0; --t )
14538  {
14539  /* check if at time point t the worst case resource profile exceeds the capacity */
14540  if( loads[t] > capacity )
14541  {
14542  assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14543  return timepoints[t+1];
14544  }
14545  }
14546 
14547  return INT_MIN;
14548 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
static SCIP_RETCODE consdataCatchEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_RETCODE SCIPbtnodeCreate(SCIP_BT *tree, SCIP_BTNODE **node, void *dataptr)
Definition: misc.c:8677
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
#define CONSHDLR_SEPAPRIORITY
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:59
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4229
int SCIPgetNCheckConss(SCIP *scip)
Definition: scip_prob.c:3184
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:1422
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
void SCIPbtnodeFree(SCIP_BT *tree, SCIP_BTNODE **node)
Definition: misc.c:8741
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:578
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:146
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:378
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:18293
static SCIP_DECL_CONSCOPY(consCopyCumulative)
#define NULL
Definition: def.h:267
enum TCLIQUE_Status TCLIQUE_STATUS
Definition: tclique.h:68
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:93
SCIP_RETCODE SCIPsolveKnapsackExactly(SCIP *scip, int nitems, SCIP_Longint *weights, SCIP_Real *profits, SCIP_Longint capacity, int *items, int *solitems, int *nonsolitems, int *nsolitems, int *nnonsolitems, SCIP_Real *solval, SCIP_Bool *success)
static SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5202
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1635
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2127
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3296
SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_setppc.c:9530
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:380
static SCIP_RETCODE consdataDropAllEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
static PROPRULE inferInfoGetProprule(INFERINFO inferinfo)
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8475
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:601
static SCIP_RETCODE checkCumulativeCondition(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *violated, SCIP_CONS *cons, SCIP_Bool printreason)
constraint handler for cumulative constraints
static SCIP_RETCODE propagateEdgeFinding(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPprofileDeleteCore(SCIP_PROFILE *profile, int left, int right, int demand)
Definition: misc.c:7050
static SCIP_RETCODE computeMinDistance(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int source, int sink, int *naddconss)
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:1991
void * SCIPbtnodeGetData(SCIP_BTNODE *node)
Definition: misc.c:8786
SCIP_RETCODE SCIPbranchVarHole(SCIP *scip, SCIP_VAR *var, SCIP_Real left, SCIP_Real right, SCIP_NODE **downchild, SCIP_NODE **upchild)
Definition: scip_branch.c:1091
void SCIPsortInd(int *indarray, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2547
int SCIPgetNVarsCumulative(SCIP *scip, SCIP_CONS *cons)
struct TCLIQUE_Graph TCLIQUE_GRAPH
Definition: tclique.h:49
static INFERINFO intToInferInfo(int i)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:354
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:941
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1658
int SCIPvarGetNVlbs(SCIP_VAR *var)
Definition: var.c:18271
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_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18079
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:831
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip_param.c:307
static void addEndingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *endtimes, int *endindices, int *freecapacity, int *idx, int nvars)
#define SCIP_MAXSTRLEN
Definition: def.h:288
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3354
#define DEFAULT_MAXNODES
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:17621
SCIP_Bool SCIPparseReal(SCIP *scip, const char *str, SCIP_Real *value, char **endptr)
void SCIPgmlWriteArc(FILE *file, unsigned int source, unsigned int target, const char *label, const char *color)
Definition: misc.c:639
SCIP_RETCODE SCIPincludeConshdlrCumulative(SCIP *scip)
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:323
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1813
static int computeOverlap(int begin, int end, int est, int lst, int duration)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2843
static SCIP_RETCODE constraintNonOverlappingGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
static void normalizeCumulativeCondition(SCIP *scip, int nvars, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
static long bound
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1701
static SCIP_RETCODE analyzeEnergyRequirement(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int begin, int end, SCIP_VAR *infervar, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation)
static void initializeLocks(SCIP_CONSDATA *consdata, SCIP_Bool locked)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
#define CONSHDLR_NAME
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18135
#define SCIP_CALL_FINALLY(x, y)
Definition: def.h:422
#define CONSHDLR_PROP_TIMING
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE createDisjuctiveCons(SCIP *scip, SCIP_CONS *cons, int *naddconss)
#define CONSHDLR_CHECKPRIORITY
static int inferInfoGetData1(INFERINFO inferinfo)
static SCIP_RETCODE solveIndependentCons(SCIP *scip, SCIP_CONS *cons, SCIP_Longint maxnodes, int *nchgbds, int *nfixedvars, int *ndelconss, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:104
static void updateKeyOnTrace(SCIP_BTNODE *node, SCIP_Real key)
void SCIPgmlWriteNode(FILE *file, unsigned int id, const char *label, const char *nodetype, const char *fillcolor, const char *bordercolor)
Definition: misc.c:497
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip_cons.c:1525
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:533
static SCIP_RETCODE presolveConsEst(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
int SCIPprofileGetTime(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6847
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1247
static SCIP_RETCODE computePeak(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *timepoint)
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:492
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_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
void SCIPgmlWriteClosing(FILE *file)
Definition: misc.c:699
SCIP_RETCODE SCIPtransformConss(SCIP *scip, int nconss, SCIP_CONS **conss, SCIP_CONS **transconss)
Definition: scip_cons.c:1626
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:10396
void SCIPbtnodeSetRightchild(SCIP_BTNODE *node, SCIP_BTNODE *right)
Definition: misc.c:8947
static SCIP_RETCODE applyAlternativeBoundsFixing(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, int *nfixedvars, SCIP_Bool *cutoff)
static SCIP_DECL_SORTPTRCOMP(compNodeEst)
#define FALSE
Definition: def.h:94
static SCIP_RETCODE collectIntVars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR ***activevars, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower, int *lhs)
static SCIP_RETCODE fixIntegerVariableLb(SCIP *scip, SCIP_VAR *var, SCIP_Bool downlock, int *nfixedvars)
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3074
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:324
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:111
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:11184
static SCIP_RETCODE consdataFreeRows(SCIP *scip, SCIP_CONSDATA **consdata)
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:181
SCIP_Real SCIPinfinity(SCIP *scip)
static SCIP_RETCODE checkOverloadViaThetaTree(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_Bool propest, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10877
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:93
#define SCIPdebug(x)
Definition: pub_message.h:93
SCIP_Real SCIPgetConflictVarUb(SCIP *scip, SCIP_VAR *var)
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
static SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
static void subtractStartingJobDemands(SCIP_CONSDATA *consdata, int curtime, int *starttimes, int *startindices, int *freecapacity, int *idx, int nvars)
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8495
int SCIPvarGetNVubs(SCIP_VAR *var)
Definition: var.c:18313
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:54
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3192
static SCIP_RETCODE presolveConsEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff)
static SCIP_RETCODE removeIrrelevantJobs(SCIP *scip, SCIP_CONS *cons)
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17769
static SCIP_RETCODE applyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_Real leftub, SCIP_Real rightlb, SCIP_Real *leftimpllbs, SCIP_Real *leftimplubs, SCIP_Real *leftproplbs, SCIP_Real *leftpropubs, SCIP_Real *rightimpllbs, SCIP_Real *rightimplubs, SCIP_Real *rightproplbs, SCIP_Real *rightpropubs, int *nfixedvars, SCIP_Bool *success, SCIP_Bool *cutoff)
static SCIP_RETCODE presolveCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nfixedvars, int *nchgbds, int *ndelconss, int *naddconss, int *nchgcoefs, int *nchgsides, SCIP_Bool *cutoff, SCIP_Bool *unbounded)
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition: scip_var.c:194
static SCIP_RETCODE strengthenVarbounds(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *naddconss)
static SCIP_RETCODE getNodeIdx(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_VAR *var, int *idx)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8525
static void conshdlrdataFree(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata)
void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
SCIP_RETCODE SCIPaddConflictRelaxedLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedlb)
#define DEFAULT_LOCALCUTS
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5319
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
static SCIP_RETCODE deleteLambdaLeaf(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
SCIP_RETCODE SCIPprofileInsertCore(SCIP_PROFILE *profile, int left, int right, int demand, int *pos, SCIP_Bool *infeasible)
Definition: misc.c:7020
#define SCIPdebugMessage
Definition: pub_message.h:96
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:235
#define CONSHDLR_DELAYPROP
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:18283
static SCIP_RETCODE separateCoverCutsCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
#define DEFAULT_USEBINVARS
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:88
static TCLIQUE_ISEDGE(tcliqueIsedgeClique)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:132
tclique user interface
static SCIP_RETCODE createCoreProfile(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3261
#define DEFAULT_COEFTIGHTENING
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
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:6660
static void normalizeDemands(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
#define SCIP_LONGINT_MAX
Definition: def.h:159
SCIP_RETCODE SCIPaddCoefKnapsack(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Longint weight)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
SCIP_RETCODE SCIPcreate(SCIP **scip)
Definition: scip_general.c:307
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:17631
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:102
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:596
#define DEFAULT_TTEFCHECK
static void createSelectedSortedEventpointsSol(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol, int *starttimes, int *endtimes, int *startindices, int *endindices, int *nvars, SCIP_Bool lower)
static SCIP_DECL_CONSINITLP(consInitlpCumulative)
SCIP_RETCODE SCIPsetRealParam(SCIP *scip, const char *name, SCIP_Real value)
Definition: scip_param.c:603
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8485
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:624
static SCIP_RETCODE propagateAllConss(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *nfixedvars, SCIP_Bool *cutoff, SCIP_Bool *branched)
int SCIPprofileGetLoad(SCIP_PROFILE *profile, int pos)
Definition: misc.c:6859
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:1479
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:808
SCIP_RETCODE SCIPsetSolveCumulative(SCIP *scip, SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)))
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8277
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
static SCIP_DECL_CONSPRESOL(consPresolCumulative)
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:998
SCIP_RETCODE SCIPcreateProbBasic(SCIP *scip, const char *name)
Definition: scip_prob.c:180
#define DEFAULT_NORMALIZE
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:52
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
static SCIP_RETCODE deleteTrivilCons(SCIP *scip, SCIP_CONS *cons, int *ndelconss, SCIP_Bool *cutoff)
SCIP_Bool SCIPexistsConsLinking(SCIP *scip, SCIP_VAR *linkvar)
SCIP_Bool SCIPbtnodeIsRoot(SCIP_BTNODE *node)
Definition: misc.c:8846
SCIP_RETCODE SCIPsolveCumulative(SCIP *scip, int njobs, SCIP_Real *ests, SCIP_Real *lsts, SCIP_Real *objvals, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Real timelimit, SCIP_Real memorylimit, SCIP_Longint maxnodes, SCIP_Bool *solved, SCIP_Bool *infeasible, SCIP_Bool *unbounded, SCIP_Bool *error)
static SCIP_RETCODE respropCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, INFERINFO inferinfo, SCIP_BOUNDTYPE boundtype, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedbd, SCIP_Bool usebdwidening, SCIP_Bool *explanation, SCIP_RESULT *result)
static SCIP_RETCODE removeOversizedJobs(SCIP *scip, SCIP_CONS *cons, int *nchgbds, int *nchgcoefs, int *naddconss, SCIP_Bool *cutoff)
static SCIP_RETCODE createConsCumulative(SCIP *scip, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
enum Proprule PROPRULE
static SCIP_RETCODE adjustOversizedJobBounds(SCIP *scip, SCIP_CONSDATA *consdata, int pos, int *nchgbds, int *naddconss, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPcreateConsVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_Bool isConsIndependently(SCIP_CONS *cons)
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:2296
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)
static void freeTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
#define CONSHDLR_DESC
#define MIN3(x, y, z)
Definition: def.h:251
static void createSortedEventpointsSol(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices)
static SCIP_RETCODE conshdlrdataCreate(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata, SCIP_EVENTHDLR *eventhdlr)
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17523
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3423
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4258
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
static SCIP_RETCODE enforceSolution(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool branch, SCIP_RESULT *result)
static SCIP_RETCODE separateConsBinaryRepresentation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetConsSeparated(SCIP *scip, SCIP_CONS *cons, SCIP_Bool separate)
Definition: scip_cons.c:1297
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_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:18089
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:105
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_VAR **vars, SCIP_CONS **linkingconss, int *durations, int *demands, int nvars, int capacity, int hmin, int hmax, SCIP_Bool check)
Constraint handler for knapsack constraints of the form , x binary and .
static const NodeData nodedata[]
Definition: gastrans.c:83
#define CONSHDLR_EAGERFREQ
#define CONSHDLR_PRESOLTIMING
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:53
SCIP_RETCODE SCIPsolve(SCIP *scip)
Definition: scip_solve.c:2498
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:347
static SCIP_RETCODE collectBranchingCands(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nbranchcands)
#define CONSHDLR_DELAYSEPA
static SCIP_RETCODE findCumulativeConss(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int *naddconss)
static int inferInfoGetData2(INFERINFO inferinfo)
#define EVENTHDLR_NAME
static SCIP_RETCODE propagateTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static SCIP_DECL_CONSLOCK(consLockCumulative)
SCIP_BTNODE * SCIPbtnodeGetParent(SCIP_BTNODE *node)
Definition: misc.c:8796
SCIP_Real * SCIPgetValsLinking(SCIP *scip, SCIP_CONS *cons)
#define SCIPerrorMessage
Definition: pub_message.h:64
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4199
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2770
static SCIP_RETCODE projectVbd(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph)
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 createTcliqueGraph(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
void SCIPsortDownPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3474
int SCIPgetHmaxCumulative(SCIP *scip, SCIP_CONS *cons)
int SCIPcomputeHmin(SCIP *scip, SCIP_PROFILE *profile, int capacity)
void SCIPbtnodeSetLeftchild(SCIP_BTNODE *node, SCIP_BTNODE *left)
Definition: misc.c:8933
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_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)
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:122
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip_var.c:1793
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)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:137
SCIP_RETCODE SCIPsetBoolParam(SCIP *scip, const char *name, SCIP_Bool value)
Definition: scip_param.c:429
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:498
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
SCIP_Real SCIPgetConflictVarLb(SCIP *scip, SCIP_VAR *var)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
void SCIPstrCopySection(const char *str, char startchar, char endchar, char *token, int size, char **endptr)
Definition: misc.c:11007
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4436
static void traceLambdaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
static SCIP_RETCODE computeEffectiveHorizon(SCIP *scip, SCIP_CONS *cons, int *ndelconss, int *naddconss, int *nchgsides)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8216
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)
static int computeEstOmegaset(SCIP *scip, int duration, int demand, int capacity, int est, int lct, int energy)
SCIP_Real * SCIPvarGetVubConstants(SCIP_VAR *var)
Definition: var.c:18345
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8714
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8435
static SCIP_RETCODE branch(SCIP *scip, SCIP_BRANCHRULE *branchrule, SCIP_RESULT *result)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:173
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17420
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:372
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3108
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4219
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)
static TCLIQUE_NEWSOL(tcliqueNewsolClique)
static SCIP_RETCODE coretimesUpdateLb(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, SCIP_PROFILE *profile, int idx, int *nchgbds, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *infeasible)
static SCIP_RETCODE createCumulativeCons(SCIP *scip, const char *name, TCLIQUE_GRAPH *tcliquegraph, int *cliquenodes, int ncliquenodes)
int SCIPcomputeHmax(SCIP *scip, SCIP_PROFILE *profile, int capacity)
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
void tcliqueMaxClique(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, TCLIQUE_WEIGHT maxfirstnodeweight, TCLIQUE_WEIGHT minweight, int maxntreenodes, int backtrackfreq, int maxnzeroextensions, int fixednode, int *ntreenodes, TCLIQUE_STATUS *status)
#define CONSHDLR_MAXPREROUNDS
static SCIP_RETCODE createCoverCuts(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss, SCIP_Bool *infeasible)
static 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:380
enum Proprule PROPRULE
Definition: cons_and.c:180
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:61
SCIP_Real * SCIPvarGetVlbConstants(SCIP_VAR *var)
Definition: var.c:18303
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)
void SCIPsortDownIntIntInt(int *intarray1, int *intarray2, int *intarray3, int len)
#define SCIPstatisticPrintf
Definition: pub_message.h:126
SCIP_RETCODE SCIPsetEmphasis(SCIP *scip, SCIP_PARAMEMPHASIS paramemphasis, SCIP_Bool quiet)
Definition: scip_param.c:882
static TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
SCIP_RETCODE SCIPcreateWorstCaseProfile(SCIP *scip, SCIP_PROFILE *profile, int nvars, SCIP_VAR **vars, int *durations, int *demands)
SCIP_RETCODE SCIPprofileCreate(SCIP_PROFILE **profile, int capacity)
Definition: misc.c:6755
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:18335
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8455
#define DEFAULT_PRESOLPAIRWISE
SCIP_RETCODE SCIPcreateConsBasicKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity)
SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1139
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:250
int * SCIPgetDurationsCumulative(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_DETECTDISJUNCTIVE
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:647
static SCIP_DECL_CONSFREE(consFreeCumulative)
SCIP_Bool SCIPbtnodeIsRightchild(SCIP_BTNODE *node)
Definition: misc.c:8884
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:123
static SCIP_RETCODE consCapacityConstraintsFinder(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
SCIP_BTNODE * SCIPbtGetRoot(SCIP_BT *tree)
Definition: misc.c:9069
static void collectDataTTEF(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int hmin, int hmax, int *permests, int *ests, int *permlcts, int *lcts, int *ects, int *lsts, int *flexenergies)
SCIP_RETCODE SCIPpropCumulativeCondition(SCIP *scip, SCIP_PRESOLTIMING presoltiming, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_CONS *cons, int *nchgbds, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPsetHminCumulative(SCIP *scip, SCIP_CONS *cons, int hmin)
static SCIP_RETCODE consCheckRedundancy(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_Bool *redundant)
constraint handler for linking binary variables to a linking (continuous or integer) variable ...
SCIP_RETCODE SCIPsplitCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int *hmin, int *hmax, int *split)
SCIP_BTNODE * SCIPbtnodeGetRightchild(SCIP_BTNODE *node)
Definition: misc.c:8816
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIP_UNKNOWN
Definition: def.h:194
static SCIP_RETCODE propagateUbTTEF(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, int *newlbs, int *newubs, int *lbinferinfos, int *ubinferinfos, int *lsts, int *flexenergies, int *perm, int *ests, int *lcts, int *coreEnergyAfterEst, int *coreEnergyAfterLct, SCIP_Bool *initialized, SCIP_Bool *explanation, SCIP_Bool *cutoff)
static void traceThetaEnvelop(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
#define SCIP_Bool
Definition: def.h:91
static SCIP_RETCODE presolveConsLct(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int hmin, int hmax, SCIP_Bool *downlocks, SCIP_Bool *uplocks, SCIP_CONS *cons, SCIP_Bool *irrelevants, int *nfixedvars, int *nchgsides, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPincludeDefaultPlugins(SCIP *scip)
static SCIP_RETCODE consdataDropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos)
static SCIP_DECL_CONSPROP(consPropCumulative)
#define DEFAULT_DUALPRESOLVE
static SCIP_RETCODE analyseInfeasibelCoreInsertion(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferduration, int inferdemand, int inferpeak, SCIP_Bool usebdwidening, SCIP_Bool *initialized, SCIP_Bool *explanation)
#define DEFAULT_USEADJUSTEDJOBS
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_PRESOLTIMING presoltiming, int *nchgbds, int *ndelconss, SCIP_Bool *cutoff)
void SCIPprintSysError(const char *message)
Definition: misc.c:10769
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:670
#define DEFAULT_USECOVERCUTS
SCIP_Bool SCIPprofileFindLeft(SCIP_PROFILE *profile, int timepoint, int *pos)
Definition: misc.c:6873
static SCIP_DECL_EVENTEXEC(eventExecCumulative)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2537
#define SCIP_DECL_CONSEXITPRE(x)
Definition: type_cons.h:180
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8236
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11943
#define MIN(x, y)
Definition: def.h:243
SCIP_RETCODE SCIPaddConflictRelaxedUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Real relaxedub)
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip_param.c:487
void SCIPbtFree(SCIP_BT **tree)
Definition: misc.c:8977
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8345
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool cutsasconss)
SCIP_Bool SCIPbtnodeIsLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8866
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8415
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8385
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17927
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:400
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:114
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip_branch.c:665
#define SCIP_PRESOLTIMING_ALWAYS
Definition: type_timing.h:58
static SCIP_Bool inferInfoIsValid(INFERINFO inferinfo)
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8275
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
int SCIPgetNRuns(SCIP *scip)
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4350
void SCIPprofilePrint(SCIP_PROFILE *profile, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: misc.c:6785
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:785
static SCIP_RETCODE inferboundsEdgeFinding(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS *cons, SCIP_BT *tree, SCIP_BTNODE **leaves, int capacity, int ncands, SCIP_Bool propest, int shift, SCIP_Bool *initialized, SCIP_Bool *explanation, int *nchgbds, SCIP_Bool *cutoff)
static SCIP_RETCODE consdataDeletePos(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_CONS *cons, int pos)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
#define CONSHDLR_NEEDSCONS
int * SCIPprofileGetTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6827
int SCIPconvertRealToInt(SCIP *scip, SCIP_Real real)
static SCIP_RETCODE computeImpliedEst(SCIP *scip, SCIP_VAR *var, SCIP_HASHMAP *addedvars, int *est)
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5500
static SCIP_RETCODE tightenCoefs(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs)
static SCIP_DECL_SORTINDCOMP(compNodedataLct)
#define DEFAULT_FILLBRANCHCANDS
static SCIP_Bool checkDemands(SCIP *scip, SCIP_CONS *cons)
int * SCIPprofileGetLoads(SCIP_PROFILE *profile)
Definition: misc.c:6837
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:97
SCIP_RETCODE SCIPsetCharParam(SCIP *scip, const char *name, char value)
Definition: scip_param.c:661
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2346
SCIP_Bool SCIPbtIsEmpty(SCIP_BT *tree)
Definition: misc.c:9059
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
#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)
static SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
SCIP_BTNODE * SCIPbtnodeGetLeftchild(SCIP_BTNODE *node)
Definition: misc.c:8806
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:59
static void createSortedEventpoints(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *starttimes, int *endtimes, int *startindices, int *endindices, SCIP_Bool local)
#define SCIP_LONGINT_FORMAT
Definition: def.h:165
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:516
SCIP_RETCODE SCIPnormalizeCumulativeCondition(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int *capacity, int *nchgcoefs, int *nchgsides)
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)
SCIP_VAR ** b
Definition: circlepacking.c:65
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1562
void SCIPbtSetRoot(SCIP_BT *tree, SCIP_BTNODE *root)
Definition: misc.c:9082
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3439
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:134
#define MAX(x, y)
Definition: def.h:239
SCIP_RETCODE SCIPapplyProbingVar(SCIP *scip, SCIP_VAR **vars, int nvars, int probingpos, SCIP_BOUNDTYPE boundtype, SCIP_Real bound, int maxproprounds, SCIP_Real *impllbs, SCIP_Real *implubs, SCIP_Real *proplbs, SCIP_Real *propubs, SCIP_Bool *cutoff)
#define CONSHDLR_SEPAFREQ
void SCIPbtnodeSetParent(SCIP_BTNODE *node, SCIP_BTNODE *parent)
Definition: misc.c:8919
static SCIP_RETCODE removeRedundantConss(SCIP *scip, SCIP_CONS **conss, int nconss, int *ndelconss)
static SCIP_RETCODE getActiveVar(SCIP *scip, SCIP_VAR **var, int *scalar, int *constant)
int * SCIPgetDemandsCumulative(SCIP *scip, SCIP_CONS *cons)
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5538
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2169
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE computeAlternativeBounds(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool local, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks)
static void traceLambdaEnergy(SCIP_BTNODE *node, SCIP_BTNODE **omegaset, int *nelements, int *est, int *lct, int *energy)
SCIP_Longint SCIPgetMemUsed(SCIP *scip)
Definition: scip_mem.c:100
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:711
static SCIP_DECL_CONSPRINT(consPrintCumulative)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1668
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8246
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:5614
static SCIP_RETCODE consdataCollectLinkingCons(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip_solve.c:3485
static SCIP_RETCODE initializeDurations(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
SCIP_RETCODE SCIPgetBinvarsLinking(SCIP *scip, SCIP_CONS *cons, SCIP_VAR ***binvars, int *nbinvars)
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip_cons.c:1322
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnvelop(SCIP_BTNODE *node)
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3042
static SCIP_RETCODE constructIncompatibilityGraph(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_CONS **conss, int nconss)
SCIP_RETCODE SCIPsetHmaxCumulative(SCIP *scip, SCIP_CONS *cons, int hmax)
static SCIP_RETCODE moveNodeToLambda(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1174
#define DEFAULT_CUTSASCONSS
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)
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:540
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:129
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:2010
static SCIP_RETCODE resolvePropagationCoretimes(SCIP *scip, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity, int hmin, int hmax, SCIP_VAR *infervar, int inferdemand, int inferpeak, int relaxedpeak, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool usebdwidening, int *provedpeak, SCIP_Bool *explanation)
SCIP_Longint SCIPgetMemExternEstim(SCIP *scip)
Definition: scip_mem.c:126
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1947
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17539
#define SCIPstatistic(x)
Definition: pub_message.h:120
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:8400
static SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
int SCIPgetHminCumulative(SCIP *scip, SCIP_CONS *cons)
#define SCIP_Real
Definition: def.h:173
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8465
static SCIP_RETCODE applyAlternativeBoundsBranching(SCIP *scip, SCIP_VAR **vars, int nvars, int *alternativelbs, int *alternativeubs, int *downlocks, int *uplocks, SCIP_Bool *branched)
static SCIP_DECL_CONSPARSE(consParseCumulative)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:724
static SCIP_DECL_CONSTRANS(consTransCumulative)
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:854
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:401
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
static SCIP_RETCODE fixIntegerVariableUb(SCIP *scip, SCIP_VAR *var, SCIP_Bool uplock, int *nfixedvars)
#define DEFAULT_EFCHECK
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8405
#define SCIP_INVALID
Definition: def.h:193
static SCIP_RETCODE insertThetanode(SCIP *scip, SCIP_BT *tree, SCIP_BTNODE *node, SCIP_NODEDATA *nodedatas, int *nodedataidx, int *nnodedatas)
#define EVENTHDLR_DESC
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8395
Proprule
Definition: cons_and.c:172
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2212
SCIP_CONS * SCIPgetConsLinking(SCIP *scip, SCIP_VAR *linkvar)
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:18325
#define DEFAULT_TTEFINFER
void SCIPsortInt(int *intarray, int len)
static SCIP_RETCODE createPrecedenceCons(SCIP *scip, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, int distance)
static INFERINFO getInferInfo(PROPRULE proprule, int data1, int data2)
#define SCIP_Longint
Definition: def.h:158
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17759
static SCIP_RETCODE detectRedundantConss(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, int *naddconss)
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2167
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17585
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2659
static SCIP_RETCODE varMayRoundUp(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
static void consdataCalcSignature(SCIP_CONSDATA *consdata)
#define DEFAULT_EFINFER
#define nnodes
Definition: gastrans.c:74
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18145
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:111
void SCIPgmlWriteOpening(FILE *file, SCIP_Bool directed)
Definition: misc.c:683
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17562
static SCIP_Bool impliesVlbPrecedenceCondition(SCIP *scip, SCIP_VAR *vlbvar, SCIP_Real vlbcoef, SCIP_Real vlbconst, int duration)
#define DEFAULT_DISJUNCTIVE
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
#define DEFAULT_USEBDWIDENING
int SCIPgetCapacityCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE tightenCapacity(SCIP *scip, SCIP_CONS *cons, int *nchgcoefs, int *nchgsides)
SCIP_RETCODE SCIPcreateConsBasicSetpart(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars)
Definition: cons_setppc.c:9399
void SCIPswapInts(int *value1, int *value2)
Definition: misc.c:10370
SCIP_RETCODE SCIPbtCreate(SCIP_BT **tree, BMS_BLKMEM *blkmem)
Definition: misc.c:8958
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3281
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 SCIPcreateConsBasicCumulative(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int *durations, int *demands, int capacity)
int TCLIQUE_WEIGHT
Definition: tclique.h:48
SCIP_VAR ** SCIPgetVarsCumulative(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSINITPRE(consInitpreCumulative)
static SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
static SCIP_RETCODE computeImpliedLct(SCIP *scip, SCIP_VAR *var, int duration, SCIP_HASHMAP *addedvars, int *lct)
int SCIPprofileGetNTimepoints(SCIP_PROFILE *profile)
Definition: misc.c:6817
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:468
#define SCIPABORT()
Definition: def.h:352
static SCIP_DECL_CONSDELETE(consDeleteCumulative)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:9121
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1217
default SCIP plugins
static SCIP_BTNODE * findResponsibleLambdaLeafTraceEnergy(SCIP_BTNODE *node)
static SCIP_DECL_CONSSEPALP(consSepalpCumulative)
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *violated, SCIP_Bool printreason)
SCIP_RETCODE SCIPvisualizeConsCumulative(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8628
SCIP_RETCODE SCIPsetSubscipsOff(SCIP *scip, SCIP_Bool quiet)
Definition: scip_param.c:904
static SCIP_RETCODE createCapacityRestrictionIntvars(SCIP *scip, SCIP_CONS *cons, int *startindices, int curtime, int nstarted, int nfinished, SCIP_Bool lower, SCIP_Bool *cutoff)
SCIP_Bool SCIPbtnodeIsLeaf(SCIP_BTNODE *node)
Definition: misc.c:8856
SCIP_RETCODE SCIPsetLongintParam(SCIP *scip, const char *name, SCIP_Longint value)
Definition: scip_param.c:545
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 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_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:57
static SCIP_DECL_CONSRESPROP(consRespropCumulative)
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17749
static SCIP_RETCODE varMayRoundDown(SCIP *scip, SCIP_VAR *var, SCIP_Bool *roundable)
void SCIPprofileFree(SCIP_PROFILE **profile)
Definition: misc.c:6769
#define CONSHDLR_ENFOPRIORITY
SCIP_RETCODE SCIPfree(SCIP **scip)
Definition: scip_general.c:339
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:128
static SCIP_Bool impliesVubPrecedenceCondition(SCIP *scip, SCIP_VAR *var, SCIP_Real vubcoef, SCIP_Real vubconst, int duration)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:281
#define DEFAULT_SEPAOLD
SCIP_RETCODE SCIPsetConsInitial(SCIP *scip, SCIP_CONS *cons, SCIP_Bool initial)
Definition: scip_cons.c:1272