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:
1389  case SCIP_STATUS_SOLLIMIT:
1392  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1393  return SCIP_INVALIDDATA;
1394  }
1395  }
1396 
1397  /* release all variables */
1398  for( v = 0; v < njobs; ++v )
1399  {
1400  SCIP_CALL( SCIPreleaseVar(subscip, &subvars[v]) );
1401  }
1402 
1403  SCIPfreeBlockMemoryArray(subscip, &subvars, njobs);
1404 
1405  return SCIP_OKAY;
1406 }
1407 
1408 /** solve single cumulative condition using SCIP and a single cumulative constraint */
1409 static
1410 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipCp)
1412  SCIP* subscip;
1413 
1414  SCIP_RETCODE retcode;
1415 
1416  assert(njobs > 0);
1417 
1418  (*solved) = FALSE;
1419  (*infeasible) = FALSE;
1420  (*unbounded) = FALSE;
1421  (*error) = FALSE;
1422 
1423  SCIPdebugMessage("solve independent cumulative condition with %d variables\n", njobs);
1424 
1425  /* initialize the sub-problem */
1426  SCIP_CALL( SCIPcreate(&subscip) );
1427 
1428  /* create and solve the subproblem. catch possible errors */
1429  retcode = setupAndSolveCumulativeSubscip(subscip, objvals, durations, demands,
1430  njobs, capacity, hmin, hmax,
1431  maxnodes, timelimit, memorylimit,
1432  ests, lsts,
1433  infeasible, unbounded, solved, error);
1434 
1435  /* free the subscip in any case */
1436  SCIP_CALL( SCIPfree(&subscip) );
1437 
1438  SCIP_CALL( retcode );
1439 
1440  return SCIP_OKAY;
1441 }
1442 
1443 #if 0
1444 /** solve single cumulative condition using SCIP and the time indexed formulation */
1445 static
1446 SCIP_DECL_SOLVECUMULATIVE(solveCumulativeViaScipMip)
1447 {
1448  SCIP* subscip;
1449  SCIP_VAR*** binvars;
1450  SCIP_RETCODE retcode;
1451  char name[SCIP_MAXSTRLEN];
1452  int minest;
1453  int maxlct;
1454  int t;
1455  int v;
1456 
1457  assert(njobs > 0);
1458 
1459  (*solved) = FALSE;
1460  (*infeasible) = FALSE;
1461  (*unbounded) = FALSE;
1462  (*error) = FALSE;
1463 
1464  SCIPdebugMsg(scip, "solve independent cumulative condition with %d variables\n", njobs);
1465 
1466  /* initialize the sub-problem */
1467  SCIP_CALL( SCIPcreate(&subscip) );
1468 
1469  /* copy all plugins */
1471 
1472  /* create the subproblem */
1473  SCIP_CALL( SCIPcreateProbBasic(subscip, "cumulative") );
1474 
1475  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars, njobs) );
1476 
1477  minest = INT_MAX;
1478  maxlct = INT_MIN;
1479 
1480  /* create for each job and time step a binary variable which is one if this jobs starts at this time point and a set
1481  * partitioning constrain which forces that job starts
1482  */
1483  for( v = 0; v < njobs; ++v )
1484  {
1485  SCIP_CONS* cons;
1486  SCIP_Real objval;
1487  int timeinterval;
1488  int est;
1489  int lst;
1490 
1491  if( objvals == NULL )
1492  objval = 0.0;
1493  else
1494  objval = objvals[v];
1495 
1496  est = ests[v];
1497  lst = lsts[v];
1498 
1499  /* compute number of possible start points */
1500  timeinterval = lst - est + 1;
1501  assert(timeinterval > 0);
1502 
1503  /* compute the smallest earliest start time and largest latest completion time */
1504  minest = MIN(minest, est);
1505  maxlct = MAX(maxlct, lst + durations[v]);
1506 
1507  /* construct constraint name */
1508  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d", v);
1509 
1510  SCIP_CALL( SCIPcreateConsBasicSetpart(subscip, &cons, name, 0, NULL) );
1511 
1512  SCIP_CALL( SCIPallocBufferArray(subscip, &binvars[v], timeinterval) );
1513 
1514  for( t = 0; t < timeinterval; ++t )
1515  {
1516  SCIP_VAR* binvar;
1517 
1518  /* construct varibale name */
1519  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "job_%d_time_%d", v, t + est);
1520 
1521  SCIP_CALL( SCIPcreateVarBasic(subscip, &binvar, name, 0.0, 1.0, objval, SCIP_VARTYPE_BINARY) );
1522  SCIP_CALL( SCIPaddVar(subscip, binvar) );
1523 
1524  /* add binary varibale to the set partitioning constraint which ensures that the job is started */
1525  SCIP_CALL( SCIPaddCoefSetppc(subscip, cons, binvar) );
1526 
1527  binvars[v][t] = binvar;
1528  }
1529 
1530  /* add and release the set partitioning constraint */
1531  SCIP_CALL( SCIPaddCons(subscip, cons) );
1532  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1533  }
1534 
1535  /* adjusted the smallest earliest start time and the largest latest completion time with the effective horizon */
1536  hmin = MAX(hmin, minest);
1537  hmax = MIN(hmax, maxlct);
1538  assert(hmin > INT_MIN);
1539  assert(hmax < INT_MAX);
1540  assert(hmin < hmax);
1541 
1542  /* create for each time a knapsack constraint which ensures that the resource capacity is not exceeded */
1543  for( t = hmin; t < hmax; ++t )
1544  {
1545  SCIP_CONS* cons;
1546 
1547  /* construct constraint name */
1548  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "time_%d", t);
1549 
1550  /* create an empty knapsack constraint */
1551  SCIP_CALL( SCIPcreateConsBasicKnapsack(subscip, &cons, name, 0, NULL, NULL, (SCIP_Longint)capacity) );
1552 
1553  /* add all jobs which potentially can be processed at that time point */
1554  for( v = 0; v < njobs; ++v )
1555  {
1556  int duration;
1557  int demand;
1558  int start;
1559  int end;
1560  int est;
1561  int lst;
1562  int k;
1563 
1564  est = ests[v];
1565  lst = lsts[v] ;
1566 
1567  duration = durations[v];
1568  assert(duration > 0);
1569 
1570  /* check if the varibale is processed potentially at time point t */
1571  if( t < est || t >= lst + duration )
1572  continue;
1573 
1574  demand = demands[v];
1575  assert(demand >= 0);
1576 
1577  start = MAX(t - duration + 1, est);
1578  end = MIN(t, lst);
1579 
1580  assert(start <= end);
1581 
1582  for( k = start; k <= end; ++k )
1583  {
1584  assert(binvars[v][k] != NULL);
1585  SCIP_CALL( SCIPaddCoefKnapsack(subscip, cons, binvars[v][k], (SCIP_Longint) demand) );
1586  }
1587  }
1588 
1589  /* add and release the knapsack constraint */
1590  SCIP_CALL( SCIPaddCons(subscip, cons) );
1591  SCIP_CALL( SCIPreleaseCons(subscip, &cons) );
1592  }
1593 
1594  /* do not abort subproblem on CTRL-C */
1595  SCIP_CALL( SCIPsetBoolParam(subscip, "misc/catchctrlc", FALSE) );
1596 
1597  /* disable output to console */
1598  SCIP_CALL( SCIPsetIntParam(subscip, "display/verblevel", 0) );
1599 
1600  /* set limits for the subproblem */
1601  SCIP_CALL( SCIPsetLongintParam(subscip, "limits/nodes", maxnodes) );
1602  SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) );
1603  SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) );
1604 
1605  /* solve single cumulative constraint by branch and bound */
1606  retcode = SCIPsolve(subscip);
1607 
1608  if( retcode != SCIP_OKAY )
1609  (*error) = TRUE;
1610  else
1611  {
1612  SCIPdebugMsg(scip, "solved single cumulative condition with status %d\n", SCIPgetStatus(subscip));
1613 
1614  /* evaluated solution status */
1615  switch( SCIPgetStatus(subscip) )
1616  {
1617  case SCIP_STATUS_INFORUNBD:
1619  (*infeasible) = TRUE;
1620  (*solved) = TRUE;
1621  break;
1622  case SCIP_STATUS_UNBOUNDED:
1623  (*unbounded) = TRUE;
1624  (*solved) = TRUE;
1625  break;
1626  case SCIP_STATUS_OPTIMAL:
1627  {
1628  SCIP_SOL* sol;
1629 
1630  sol = SCIPgetBestSol(subscip);
1631  assert(sol != NULL);
1632 
1633  for( v = 0; v < njobs; ++v )
1634  {
1635  int timeinterval;
1636  int est;
1637  int lst;
1638 
1639  est = ests[v];
1640  lst = lsts[v];
1641 
1642  /* compute number of possible start points */
1643  timeinterval = lst - est + 1;
1644 
1645  /* check which binary varibale is set to one */
1646  for( t = 0; t < timeinterval; ++t )
1647  {
1648  if( SCIPgetSolVal(subscip, sol, binvars[v][t]) > 0.5 )
1649  {
1650  ests[v] = est + t;
1651  lsts[v] = est + t;
1652  break;
1653  }
1654  }
1655  }
1656 
1657  (*solved) = TRUE;
1658  break;
1659  }
1660  case SCIP_STATUS_NODELIMIT:
1662  case SCIP_STATUS_TIMELIMIT:
1663  case SCIP_STATUS_MEMLIMIT:
1665  /* transfer the global bound changes */
1666  for( v = 0; v < njobs; ++v )
1667  {
1668  int timeinterval;
1669  int est;
1670  int lst;
1671 
1672  est = ests[v];
1673  lst = lsts[v];
1674 
1675  /* compute number of possible start points */
1676  timeinterval = lst - est + 1;
1677 
1678  /* check which binary varibale is the first binary varibale which is not globally fixed to zero */
1679  for( t = 0; t < timeinterval; ++t )
1680  {
1681  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1682  {
1683  ests[v] = est + t;
1684  break;
1685  }
1686  }
1687 
1688  /* check which binary varibale is the last binary varibale which is not globally fixed to zero */
1689  for( t = timeinterval - 1; t >= 0; --t )
1690  {
1691  if( SCIPvarGetUbGlobal(binvars[v][t]) > 0.5 )
1692  {
1693  lsts[v] = est + t;
1694  break;
1695  }
1696  }
1697  }
1698  (*solved) = FALSE;
1699  break;
1700 
1701  case SCIP_STATUS_UNKNOWN:
1703  case SCIP_STATUS_GAPLIMIT:
1704  case SCIP_STATUS_SOLLIMIT:
1706  SCIPerrorMessage("invalid status code <%d>\n", SCIPgetStatus(subscip));
1707  return SCIP_INVALIDDATA;
1708  }
1709  }
1710 
1711  /* release all variables */
1712  for( v = 0; v < njobs; ++v )
1713  {
1714  int timeinterval;
1715  int est;
1716  int lst;
1717 
1718  est = ests[v];
1719  lst = lsts[v];
1720 
1721  /* compute number of possible start points */
1722  timeinterval = lst - est + 1;
1723 
1724  for( t = 0; t < timeinterval; ++t )
1725  {
1726  SCIP_CALL( SCIPreleaseVar(subscip, &binvars[v][t]) );
1727  }
1728  SCIPfreeBufferArray(subscip, &binvars[v]);
1729  }
1730 
1731  SCIPfreeBufferArray(subscip, &binvars);
1732 
1733  SCIP_CALL( SCIPfree(&subscip) );
1734 
1735  return SCIP_OKAY;
1736 }
1737 #endif
1738 
1739 /**@} */
1740 
1741 /**@name Constraint handler data
1742  *
1743  * Method used to create and free the constraint handler data when including and removing the cumulative constraint
1744  * handler.
1745  *
1746  * @{
1747  */
1748 
1749 /** creates constaint handler data for cumulative constraint handler */
1750 static
1752  SCIP* scip, /**< SCIP data structure */
1753  SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
1754  SCIP_EVENTHDLR* eventhdlr /**< event handler */
1755  )
1756 {
1757  /* create precedence constraint handler data */
1758  assert(scip != NULL);
1759  assert(conshdlrdata != NULL);
1760  assert(eventhdlr != NULL);
1761 
1762  SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
1763 
1764  /* set event handler for checking if bounds of start time variables are tighten */
1765  (*conshdlrdata)->eventhdlr = eventhdlr;
1766 
1767  /* set default methed for solving single cumulative conditions using SCIP and a CP model */
1768  (*conshdlrdata)->solveCumulative = solveCumulativeViaScipCp;
1769 
1770 #ifdef SCIP_STATISTIC
1771  (*conshdlrdata)->nlbtimetable = 0;
1772  (*conshdlrdata)->nubtimetable = 0;
1773  (*conshdlrdata)->ncutofftimetable = 0;
1774  (*conshdlrdata)->nlbedgefinder = 0;
1775  (*conshdlrdata)->nubedgefinder = 0;
1776  (*conshdlrdata)->ncutoffedgefinder = 0;
1777  (*conshdlrdata)->ncutoffoverload = 0;
1778  (*conshdlrdata)->ncutoffoverloadTTEF = 0;
1779 
1780  (*conshdlrdata)->nirrelevantjobs = 0;
1781  (*conshdlrdata)->nalwaysruns = 0;
1782  (*conshdlrdata)->nremovedlocks = 0;
1783  (*conshdlrdata)->ndualfixs = 0;
1784  (*conshdlrdata)->ndecomps = 0;
1785  (*conshdlrdata)->ndualbranchs = 0;
1786  (*conshdlrdata)->nallconsdualfixs = 0;
1787  (*conshdlrdata)->naddedvarbounds = 0;
1788  (*conshdlrdata)->naddeddisjunctives = 0;
1789 #endif
1790 
1791  return SCIP_OKAY;
1792 }
1793 
1794 /** frees constraint handler data for logic or constraint handler */
1795 static
1796 void conshdlrdataFree(
1797  SCIP* scip, /**< SCIP data structure */
1798  SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
1799  )
1800 {
1801  assert(conshdlrdata != NULL);
1802  assert(*conshdlrdata != NULL);
1803 
1804  SCIPfreeBlockMemory(scip, conshdlrdata);
1805 }
1806 
1807 /**@} */
1808 
1809 
1810 /**@name Constraint data methods
1811  *
1812  * @{
1813  */
1814 
1815 /** catches bound change events for all variables in transformed cumulative constraint */
1816 static
1818  SCIP* scip, /**< SCIP data structure */
1819  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1820  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1821  )
1822 {
1823  int v;
1824 
1825  assert(scip != NULL);
1826  assert(consdata != NULL);
1827  assert(eventhdlr != NULL);
1828 
1829  /* catch event for every single variable */
1830  for( v = 0; v < consdata->nvars; ++v )
1831  {
1832  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v],
1833  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
1834  }
1835 
1836  return SCIP_OKAY;
1837 }
1838 
1839 /** drops events for variable at given position */
1840 static
1842  SCIP* scip, /**< SCIP data structure */
1843  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
1844  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1845  int pos /**< array position of variable to catch bound change events for */
1846  )
1847 {
1848  assert(scip != NULL);
1849  assert(consdata != NULL);
1850  assert(eventhdlr != NULL);
1851  assert(0 <= pos && pos < consdata->nvars);
1852  assert(consdata->vars[pos] != NULL);
1853 
1854  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
1855  SCIP_EVENTTYPE_BOUNDTIGHTENED, eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
1856 
1857  return SCIP_OKAY;
1858 }
1859 
1860 /** drops bound change events for all variables in transformed linear constraint */
1861 static
1863  SCIP* scip, /**< SCIP data structure */
1864  SCIP_CONSDATA* consdata, /**< linear constraint data */
1865  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1866  )
1867 {
1868  int v;
1869 
1870  assert(scip != NULL);
1871  assert(consdata != NULL);
1872 
1873  /* drop event of every single variable */
1874  for( v = 0; v < consdata->nvars; ++v )
1875  {
1876  SCIP_CALL( consdataDropEvents(scip, consdata, eventhdlr, v) );
1877  }
1878 
1879  return SCIP_OKAY;
1880 }
1881 
1882 /** initialize variable lock data structure */
1883 static
1884 void initializeLocks(
1885  SCIP_CONSDATA* consdata, /**< constraint data */
1886  SCIP_Bool locked /**< should the variable be locked? */
1887  )
1888 {
1889  int nvars;
1890  int v;
1891 
1892  nvars = consdata->nvars;
1893 
1894  /* initialize locking arrays */
1895  for( v = 0; v < nvars; ++v )
1896  {
1897  consdata->downlocks[v] = locked;
1898  consdata->uplocks[v] = locked;
1899  }
1900 }
1901 
1902 /** creates constraint data of cumulative constraint */
1903 static
1905  SCIP* scip, /**< SCIP data structure */
1906  SCIP_CONSDATA** consdata, /**< pointer to consdata */
1907  SCIP_VAR** vars, /**< array of integer variables */
1908  SCIP_CONS** linkingconss, /**< array of linking constraints for the integer variables, or NULL */
1909  int* durations, /**< array containing corresponding durations */
1910  int* demands, /**< array containing corresponding demands */
1911  int nvars, /**< number of variables */
1912  int capacity, /**< available cumulative capacity */
1913  int hmin, /**< left bound of time axis to be considered (including hmin) */
1914  int hmax, /**< right bound of time axis to be considered (not including hmax) */
1915  SCIP_Bool check /**< is the corresponding constraint a check constraint */
1916  )
1917 {
1918  int v;
1919 
1920  assert(scip != NULL);
1921  assert(consdata != NULL);
1922  assert(vars != NULL || nvars > 0);
1923  assert(demands != NULL);
1924  assert(durations != NULL);
1925  assert(capacity >= 0);
1926  assert(hmin >= 0);
1927  assert(hmin < hmax);
1928 
1929  /* create constraint data */
1930  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1931 
1932  (*consdata)->hmin = hmin;
1933  (*consdata)->hmax = hmax;
1934 
1935  (*consdata)->capacity = capacity;
1936  (*consdata)->demandrows = NULL;
1937  (*consdata)->demandrowssize = 0;
1938  (*consdata)->ndemandrows = 0;
1939  (*consdata)->scoverrows = NULL;
1940  (*consdata)->nscoverrows = 0;
1941  (*consdata)->scoverrowssize = 0;
1942  (*consdata)->bcoverrows = NULL;
1943  (*consdata)->nbcoverrows = 0;
1944  (*consdata)->bcoverrowssize = 0;
1945  (*consdata)->nvars = nvars;
1946  (*consdata)->varssize = nvars;
1947  (*consdata)->signature = 0;
1948  (*consdata)->validsignature = FALSE;
1949  (*consdata)->normalized = FALSE;
1950  (*consdata)->covercuts = FALSE;
1951  (*consdata)->propagated = FALSE;
1952  (*consdata)->varbounds = FALSE;
1953  (*consdata)->triedsolving = FALSE;
1954 
1955  if( nvars > 0 )
1956  {
1957  assert(vars != NULL); /* for flexelint */
1958 
1959  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
1960  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->demands, demands, nvars) );
1961  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->durations, durations, nvars) );
1962  (*consdata)->linkingconss = NULL;
1963 
1964  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->downlocks, nvars) );
1965  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->uplocks, nvars) );
1966 
1967  /* initialize variable lock data structure; the locks are only used if the constraint is a check constraint */
1968  initializeLocks(*consdata, check);
1969 
1970  if( linkingconss != NULL )
1971  {
1972  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linkingconss, linkingconss, nvars) );
1973  }
1974 
1975  /* transform variables, if they are not yet transformed */
1976  if( SCIPisTransformed(scip) )
1977  {
1978  SCIPdebugMsg(scip, "get tranformed variables and constraints\n");
1979 
1980  /* get transformed variables and do NOT captures these */
1981  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1982 
1983  /* multi-aggregated variables cannot be replaced by active variable; therefore we mark all variables for not
1984  * been multi-aggregated
1985  */
1986  for( v = 0; v < nvars; ++v )
1987  {
1988  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
1989  }
1990 
1991  if( linkingconss != NULL )
1992  {
1993  /* get transformed constraints and captures these */
1994  SCIP_CALL( SCIPtransformConss(scip, (*consdata)->nvars, (*consdata)->linkingconss, (*consdata)->linkingconss) );
1995 
1996  for( v = 0; v < nvars; ++v )
1997  assert(SCIPgetConsLinking(scip, (*consdata)->vars[v]) == (*consdata)->linkingconss[v]);
1998  }
1999  }
2000 
2001 #ifndef NDEBUG
2002  /* only binary and integer variables can be used in cumulative constraints
2003  * for fractional variable values, the constraint cannot be checked
2004  */
2005  for( v = 0; v < (*consdata)->nvars; ++v )
2006  assert(SCIPvarGetType((*consdata)->vars[v]) <= SCIP_VARTYPE_INTEGER);
2007 #endif
2008  }
2009  else
2010  {
2011  (*consdata)->vars = NULL;
2012  (*consdata)->downlocks = NULL;
2013  (*consdata)->uplocks = NULL;
2014  (*consdata)->demands = NULL;
2015  (*consdata)->durations = NULL;
2016  (*consdata)->linkingconss = NULL;
2017  }
2018 
2019  /* initialize values for running propagation algorithms efficiently */
2020  (*consdata)->resstrength1 = -1.0;
2021  (*consdata)->resstrength2 = -1.0;
2022  (*consdata)->cumfactor1 = -1.0;
2023  (*consdata)->disjfactor1 = -1.0;
2024  (*consdata)->disjfactor2 = -1.0;
2025  (*consdata)->estimatedstrength = -1.0;
2026 
2027  SCIPstatistic( (*consdata)->maxpeak = -1 );
2028 
2029  return SCIP_OKAY;
2030 }
2031 
2032 /** releases LP rows of constraint data and frees rows array */
2033 static
2035  SCIP* scip, /**< SCIP data structure */
2036  SCIP_CONSDATA** consdata /**< constraint data */
2037  )
2038 {
2039  int r;
2040 
2041  assert(consdata != NULL);
2042  assert(*consdata != NULL);
2043 
2044  for( r = 0; r < (*consdata)->ndemandrows; ++r )
2045  {
2046  assert((*consdata)->demandrows[r] != NULL);
2047  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->demandrows[r]) );
2048  }
2049 
2050  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->demandrows, (*consdata)->demandrowssize);
2051 
2052  (*consdata)->ndemandrows = 0;
2053  (*consdata)->demandrowssize = 0;
2054 
2055  /* free rows of cover cuts */
2056  for( r = 0; r < (*consdata)->nscoverrows; ++r )
2057  {
2058  assert((*consdata)->scoverrows[r] != NULL);
2059  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->scoverrows[r]) );
2060  }
2061 
2062  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->scoverrows, (*consdata)->scoverrowssize);
2063 
2064  (*consdata)->nscoverrows = 0;
2065  (*consdata)->scoverrowssize = 0;
2066 
2067  for( r = 0; r < (*consdata)->nbcoverrows; ++r )
2068  {
2069  assert((*consdata)->bcoverrows[r] != NULL);
2070  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->bcoverrows[r]) );
2071  }
2072 
2073  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bcoverrows, (*consdata)->bcoverrowssize);
2074 
2075  (*consdata)->nbcoverrows = 0;
2076  (*consdata)->bcoverrowssize = 0;
2077 
2078  (*consdata)->covercuts = FALSE;
2079 
2080  return SCIP_OKAY;
2081 }
2082 
2083 /** frees a cumulative constraint data */
2084 static
2086  SCIP* scip, /**< SCIP data structure */
2087  SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
2088  )
2089 {
2090  int varssize;
2091  int nvars;
2092 
2093  assert(consdata != NULL);
2094  assert(*consdata != NULL);
2095 
2096  nvars = (*consdata)->nvars;
2097  varssize = (*consdata)->varssize;
2098 
2099  if( varssize > 0 )
2100  {
2101  int v;
2102 
2103  /* release and free the rows */
2104  SCIP_CALL( consdataFreeRows(scip, consdata) );
2105 
2106  /* release the linking constraints if they were generated */
2107  if( (*consdata)->linkingconss != NULL )
2108  {
2109  for( v = nvars-1; v >= 0; --v )
2110  {
2111  assert((*consdata)->linkingconss[v] != NULL );
2112  SCIP_CALL( SCIPreleaseCons(scip, &(*consdata)->linkingconss[v]) );
2113  }
2114 
2115  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linkingconss, varssize);
2116  }
2117 
2118  /* free arrays */
2119  SCIPfreeBlockMemoryArray(scip, &(*consdata)->downlocks, varssize);
2120  SCIPfreeBlockMemoryArray(scip, &(*consdata)->uplocks, varssize);
2121  SCIPfreeBlockMemoryArray(scip, &(*consdata)->durations, varssize);
2122  SCIPfreeBlockMemoryArray(scip, &(*consdata)->demands, varssize);
2123  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, varssize);
2124  }
2125 
2126  /* free memory */
2127  SCIPfreeBlockMemory(scip, consdata);
2128 
2129  return SCIP_OKAY;
2130 }
2131 
2132 /** prints cumulative constraint to file stream */
2133 static
2134 void consdataPrint(
2135  SCIP* scip, /**< SCIP data structure */
2136  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2137  FILE* file /**< output file (or NULL for standard output) */
2138  )
2139 {
2140  int v;
2141 
2142  assert(consdata != NULL);
2143 
2144  /* print coefficients */
2145  SCIPinfoMessage( scip, file, "cumulative(");
2146 
2147  for( v = 0; v < consdata->nvars; ++v )
2148  {
2149  assert(consdata->vars[v] != NULL);
2150  if( v > 0 )
2151  SCIPinfoMessage(scip, file, ", ");
2152  SCIPinfoMessage(scip, file, "<%s>[%g,%g](%d)[%d]", SCIPvarGetName(consdata->vars[v]),
2153  SCIPvarGetLbGlobal(consdata->vars[v]), SCIPvarGetUbGlobal(consdata->vars[v]),
2154  consdata->durations[v], consdata->demands[v]);
2155  }
2156  SCIPinfoMessage(scip, file, ")[%d,%d) <= %d", consdata->hmin, consdata->hmax, consdata->capacity);
2157 }
2158 
2159 /** deletes coefficient at given position from constraint data */
2160 static
2162  SCIP* scip, /**< SCIP data structure */
2163  SCIP_CONSDATA* consdata, /**< cumulative constraint data */
2164  SCIP_CONS* cons, /**< knapsack constraint */
2165  int pos /**< position of coefficient to delete */
2166  )
2167 {
2168  SCIP_CONSHDLR* conshdlr;
2169  SCIP_CONSHDLRDATA* conshdlrdata;
2170 
2171  assert(scip != NULL);
2172  assert(consdata != NULL);
2173  assert(cons != NULL);
2174  assert(SCIPconsIsTransformed(cons));
2175  assert(!SCIPinProbing(scip));
2176 
2177  SCIPdebugMsg(scip, "cumulative constraint <%s>: remove variable <%s>\n",
2178  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[pos]));
2179 
2180  /* remove the rounding locks for the deleted variable */
2181  SCIP_CALL( SCIPunlockVarCons(scip, consdata->vars[pos], cons, consdata->downlocks[pos], consdata->uplocks[pos]) );
2182 
2183  consdata->downlocks[pos] = FALSE;
2184  consdata->uplocks[pos] = FALSE;
2185 
2186  if( consdata->linkingconss != NULL )
2187  {
2188  SCIP_CALL( SCIPreleaseCons(scip, &consdata->linkingconss[pos]) );
2189  }
2190 
2191  /* get event handler */
2192  conshdlr = SCIPconsGetHdlr(cons);
2193  assert(conshdlr != NULL);
2194  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2195  assert(conshdlrdata != NULL);
2196  assert(conshdlrdata->eventhdlr != NULL);
2197 
2198  /* drop events */
2199  SCIP_CALL( consdataDropEvents(scip, consdata, conshdlrdata->eventhdlr, pos) );
2200 
2201  SCIPdebugMsg(scip, "remove variable <%s>[%g,%g] from cumulative constraint <%s>\n",
2202  SCIPvarGetName(consdata->vars[pos]), SCIPvarGetLbGlobal(consdata->vars[pos]), SCIPvarGetUbGlobal(consdata->vars[pos]), SCIPconsGetName(cons));
2203 
2204  /* in case the we did not remove the variable in the last slot of the arrays we move the current last to this
2205  * position
2206  */
2207  if( pos != consdata->nvars - 1 )
2208  {
2209  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
2210  consdata->downlocks[pos] = consdata->downlocks[consdata->nvars-1];
2211  consdata->uplocks[pos] = consdata->uplocks[consdata->nvars-1];
2212  consdata->demands[pos] = consdata->demands[consdata->nvars-1];
2213  consdata->durations[pos] = consdata->durations[consdata->nvars-1];
2214 
2215  if( consdata->linkingconss != NULL )
2216  {
2217  consdata->linkingconss[pos]= consdata->linkingconss[consdata->nvars-1];
2218  }
2219  }
2220 
2221  consdata->nvars--;
2222  consdata->validsignature = FALSE;
2223  consdata->normalized = FALSE;
2224 
2225  return SCIP_OKAY;
2226 }
2227 
2228 /** collect linking constraints for each integer variable */
2229 static
2231  SCIP* scip, /**< SCIP data structure */
2232  SCIP_CONSDATA* consdata /**< pointer to consdata */
2233  )
2234 {
2235  int nvars;
2236  int v;
2237 
2238  assert(scip != NULL);
2239  assert(consdata != NULL);
2240 
2241  nvars = consdata->nvars;
2242  assert(nvars > 0);
2243  assert(consdata->linkingconss == NULL);
2244 
2245  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->linkingconss, consdata->varssize) );
2246 
2247  for( v = 0; v < nvars; ++v )
2248  {
2249  SCIP_CONS* cons;
2250  SCIP_VAR* var;
2251 
2252  var = consdata->vars[v];
2253  assert(var != NULL);
2254 
2255  SCIPdebugMsg(scip, "linking constraint (%d of %d) for variable <%s>\n", v+1, nvars, SCIPvarGetName(var));
2256 
2257  /* create linking constraint if it does not exist yet */
2258  if( !SCIPexistsConsLinking(scip, var) )
2259  {
2260  char name[SCIP_MAXSTRLEN];
2261 
2262  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "link(%s)", SCIPvarGetName(var));
2263 
2264  /* creates and captures an linking constraint */
2265  SCIP_CALL( SCIPcreateConsLinking(scip, &cons, name, var, NULL, 0, 0,
2266  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE /*TRUE*/, FALSE) );
2267  SCIP_CALL( SCIPaddCons(scip, cons) );
2268  consdata->linkingconss[v] = cons;
2269  }
2270  else
2271  {
2272  consdata->linkingconss[v] = SCIPgetConsLinking(scip, var);
2273  SCIP_CALL( SCIPcaptureCons(scip, consdata->linkingconss[v]) );
2274  }
2275 
2276  assert(SCIPexistsConsLinking(scip, var));
2277  assert(consdata->linkingconss[v] != NULL);
2278  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->linkingconss[v])), "linking") == 0 );
2279  assert(SCIPgetConsLinking(scip, var) == consdata->linkingconss[v]);
2280  }
2281 
2282  return SCIP_OKAY;
2283 }
2284 
2285 /**@} */
2286 
2287 
2288 /**@name Check methods
2289  *
2290  * @{
2291  */
2292 
2293 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
2294  * given solution is satisfied
2295  */
2296 static
2298  SCIP* scip, /**< SCIP data structure */
2299  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2300  int nvars, /**< number of variables (jobs) */
2301  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
2302  int* durations, /**< array containing corresponding durations */
2303  int* demands, /**< array containing corresponding demands */
2304  int capacity, /**< available cumulative capacity */
2305  int hmin, /**< left bound of time axis to be considered (including hmin) */
2306  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2307  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
2308  SCIP_CONS* cons, /**< constraint which is checked */
2309  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2310  )
2311 {
2312  int* startsolvalues; /* stores when each job is starting */
2313  int* endsolvalues; /* stores when each job ends */
2314  int* startindices; /* we will sort the startsolvalues, thus we need to know which index of a job it corresponds to */
2315  int* endindices; /* we will sort the endsolvalues, thus we need to know which index of a job it corresponds to */
2316 
2317  int freecapacity;
2318  int curtime; /* point in time which we are just checking */
2319  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
2320  int j;
2321 
2322  SCIP_Real absviol;
2323  SCIP_Real relviol;
2324 
2325  assert(scip != NULL);
2326  assert(violated != NULL);
2327 
2328  (*violated) = FALSE;
2329 
2330  if( nvars == 0 )
2331  return SCIP_OKAY;
2332 
2333  assert(vars != NULL);
2334  assert(demands != NULL);
2335  assert(durations != NULL);
2336 
2337  /* compute time points where we have to check whether capacity constraint is infeasible or not */
2338  SCIP_CALL( SCIPallocBufferArray(scip, &startsolvalues, nvars) );
2339  SCIP_CALL( SCIPallocBufferArray(scip, &endsolvalues, nvars) );
2340  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
2341  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
2342 
2343  /* assign variables, start and endpoints to arrays */
2344  for ( j = 0; j < nvars; ++j )
2345  {
2346  int solvalue;
2347 
2348  /* the constraint of the cumulative constraint handler should be called after the integrality check */
2349  assert(SCIPisFeasIntegral(scip, SCIPgetSolVal(scip, sol, vars[j])));
2350 
2351  solvalue = SCIPconvertRealToInt(scip, SCIPgetSolVal(scip, sol, vars[j]));
2352 
2353  /* we need to ensure that we check at least one time point during the effective horizon; therefore we project all
2354  * jobs which start before hmin to hmin
2355  */
2356  startsolvalues[j] = MAX(solvalue, hmin);
2357  startindices[j] = j;
2358 
2359  endsolvalues[j] = MAX(solvalue + durations[j], hmin);
2360  endindices[j] = j;
2361  }
2362 
2363  /* sort the arrays not-decreasing according to start solution values and end solution values (and sort the
2364  * corresponding indices in the same way)
2365  */
2366  SCIPsortIntInt(startsolvalues, startindices, nvars);
2367  SCIPsortIntInt(endsolvalues, endindices, nvars);
2368 
2369  endindex = 0;
2370  freecapacity = capacity;
2371  absviol = 0.0;
2372  relviol = 0.0;
2373 
2374  /* check each start point of a job whether the capacity is kept or not */
2375  for( j = 0; j < nvars; ++j )
2376  {
2377  /* only check intervals [hmin,hmax) */
2378  curtime = startsolvalues[j];
2379 
2380  if( curtime >= hmax )
2381  break;
2382 
2383  /* subtract all capacity needed up to this point */
2384  freecapacity -= demands[startindices[j]];
2385  while( j+1 < nvars && startsolvalues[j+1] == curtime )
2386  {
2387  j++;
2388  freecapacity -= demands[startindices[j]];
2389  }
2390 
2391  /* free all capacity usages of jobs that are no longer running */
2392  while( endindex < nvars && curtime >= endsolvalues[endindex] )
2393  {
2394  freecapacity += demands[endindices[endindex]];
2395  ++endindex;
2396  }
2397  assert(freecapacity <= capacity);
2398 
2399  /* update absolute and relative violation */
2400  if( absviol < (SCIP_Real) (-freecapacity) )
2401  {
2402  absviol = -freecapacity;
2403  relviol = SCIPrelDiff((SCIP_Real)(capacity - freecapacity), (SCIP_Real)capacity);
2404  }
2405 
2406  /* check freecapacity to be smaller than zero */
2407  if( freecapacity < 0 && curtime >= hmin )
2408  {
2409  SCIPdebugMsg(scip, "freecapacity = %3d\n", freecapacity);
2410  (*violated) = TRUE;
2411 
2412  if( printreason )
2413  {
2414  int i;
2415 
2416  /* first state the violated constraints */
2417  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
2418 
2419  /* second state the reason */
2420  SCIPinfoMessage(scip, NULL,
2421  ";\nviolation: at time point %d available capacity = %d, needed capacity = %d\n",
2422  curtime, capacity, capacity - freecapacity);
2423 
2424  for( i = 0; i <= j; ++i )
2425  {
2426  if( startsolvalues[i] + durations[startindices[i]] > curtime )
2427  {
2428  SCIPinfoMessage(scip, NULL, "activity %s, start = %i, duration = %d, demand = %d \n",
2429  SCIPvarGetName(vars[startindices[i]]), startsolvalues[i], durations[startindices[i]],
2430  demands[startindices[i]]);
2431  }
2432  }
2433  }
2434  break;
2435  }
2436  } /*lint --e{850}*/
2437 
2438  /* update constraint violation in solution */
2439  if( sol != NULL )
2440  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
2441 
2442  /* free all buffer arrays */
2443  SCIPfreeBufferArray(scip, &endindices);
2444  SCIPfreeBufferArray(scip, &startindices);
2445  SCIPfreeBufferArray(scip, &endsolvalues);
2446  SCIPfreeBufferArray(scip, &startsolvalues);
2447 
2448  return SCIP_OKAY;
2449 }
2450 
2451 /** check if the given constrait is valid; checks each starting point of a job whether the remaining capacity is at
2452  * least zero or not. If not (*violated) is set to TRUE
2453  */
2454 static
2456  SCIP* scip, /**< SCIP data structure */
2457  SCIP_CONS* cons, /**< constraint to be checked */
2458  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
2459  SCIP_Bool* violated, /**< pointer to store if the constraint is violated */
2460  SCIP_Bool printreason /**< should the reason for the violation be printed? */
2461  )
2462 {
2463  SCIP_CONSDATA* consdata;
2464 
2465  assert(scip != NULL);
2466  assert(cons != NULL);
2467  assert(violated != NULL);
2468 
2469  SCIPdebugMsg(scip, "check cumulative constraints <%s>\n", SCIPconsGetName(cons));
2470 
2471  consdata = SCIPconsGetData(cons);
2472  assert(consdata != NULL);
2473 
2474  /* check the cumulative condition */
2475  SCIP_CALL( checkCumulativeCondition(scip, sol, consdata->nvars, consdata->vars,
2476  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
2477  violated, cons, printreason) );
2478 
2479  return SCIP_OKAY;
2480 }
2481 
2482 /**@} */
2483 
2484 /**@name Conflict analysis
2485  *
2486  * @{
2487  */
2488 
2489 /** resolves the propagation of the core time algorithm */
2490 static
2492  SCIP* scip, /**< SCIP data structure */
2493  int nvars, /**< number of start time variables (activities) */
2494  SCIP_VAR** vars, /**< array of start time variables */
2495  int* durations, /**< array of durations */
2496  int* demands, /**< array of demands */
2497  int capacity, /**< cumulative capacity */
2498  int hmin, /**< left bound of time axis to be considered (including hmin) */
2499  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2500  SCIP_VAR* infervar, /**< inference variable */
2501  int inferdemand, /**< demand of the inference variable */
2502  int inferpeak, /**< time point which causes the propagation */
2503  int relaxedpeak, /**< relaxed time point which would be sufficient to be proved */
2504  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2505  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2506  int* provedpeak, /**< pointer to store the actually proved peak, or NULL */
2507  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2508  )
2509 {
2510  SCIP_VAR* var;
2511  SCIP_Bool* reported;
2512  int duration;
2513  int maxlst;
2514  int minect;
2515  int ect;
2516  int lst;
2517  int j;
2518 
2519  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
2520 
2521  SCIPdebugMsg(scip, "variable <%s>: (demand %d) resolve propagation of core time algorithm (peak %d)\n",
2522  SCIPvarGetName(infervar), inferdemand, inferpeak);
2523  assert(nvars > 0);
2524 
2525  /* adjusted capacity */
2526  capacity -= inferdemand;
2527  maxlst = INT_MIN;
2528  minect = INT_MAX;
2529 
2530  SCIP_CALL( SCIPallocBufferArray(scip, &reported, nvars) );
2531  BMSclearMemoryArray(reported, nvars);
2532 
2533  /* first we loop over all variables and adjust the capacity with those jobs which provide a global core at the
2534  * inference peak and those where the current conflict bounds provide a core at the inference peak
2535  */
2536  for( j = 0; j < nvars && capacity >= 0; ++j )
2537  {
2538  var = vars[j];
2539  assert(var != NULL);
2540 
2541  /* skip inference variable */
2542  if( var == infervar )
2543  continue;
2544 
2545  duration = durations[j];
2546  assert(duration > 0);
2547 
2548  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2549  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2550  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2551  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2552  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2553 
2554  SCIPdebugMsg(scip, "variable <%s>: glb=[%g,%g] conflict=[%g,%g] (duration %d, demand %d)\n",
2556  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var), duration, demands[j]);
2557 
2558  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
2559  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
2560 
2561  /* check if the inference peak is part of the global bound core; if so we decreasing the capacity by the demand of
2562  * that job without adding it the explanation
2563  */
2564  if( inferpeak < ect && lst <= inferpeak )
2565  {
2566  capacity -= demands[j];
2567  reported[j] = TRUE;
2568 
2569  maxlst = MAX(maxlst, lst);
2570  minect = MIN(minect, ect);
2571  assert(maxlst < minect);
2572 
2573  if( explanation != NULL )
2574  explanation[j] = TRUE;
2575 
2576  continue;
2577  }
2578 
2579  /* collect the conflict bound core (the conflict bounds are those bounds which are already part of the conflict)
2580  * hence these bound are already reported by other resolve propation steps. In case a bound (lower or upper) is
2581  * not part of the conflict yet we get the global bounds back.
2582  */
2583  ect = SCIPconvertRealToInt(scip, SCIPgetConflictVarLb(scip, var)) + duration;
2584  lst = SCIPconvertRealToInt(scip, SCIPgetConflictVarUb(scip, var));
2585 
2586  /* check if the inference peak is part of the conflict bound core; if so we decreasing the capacity by the demand
2587  * of that job without and collect the job as part of the explanation
2588  *
2589  * @note we do not need to reported that job to SCIP since the required bounds are already reported
2590  */
2591  if( inferpeak < ect && lst <= inferpeak )
2592  {
2593  capacity -= demands[j];
2594  reported[j] = TRUE;
2595 
2596  maxlst = MAX(maxlst, lst);
2597  minect = MIN(minect, ect);
2598  assert(maxlst < minect);
2599 
2600  if( explanation != NULL )
2601  explanation[j] = TRUE;
2602  }
2603  }
2604 
2605  if( capacity >= 0 )
2606  {
2607  int* cands;
2608  int* canddemands;
2609  int ncands;
2610  int c;
2611 
2612  SCIP_CALL( SCIPallocBufferArray(scip, &cands, nvars) );
2613  SCIP_CALL( SCIPallocBufferArray(scip, &canddemands, nvars) );
2614  ncands = 0;
2615 
2616  /* collect all cores of the variables which lay in the considered time window except the inference variable */
2617  for( j = 0; j < nvars; ++j )
2618  {
2619  var = vars[j];
2620  assert(var != NULL);
2621 
2622  /* skip inference variable */
2623  if( var == infervar || reported[j] )
2624  continue;
2625 
2626  duration = durations[j];
2627  assert(duration > 0);
2628 
2629  /* compute cores of jobs; if core overlaps interval of inference variable add this job to the array */
2630  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)));
2631  assert(SCIPisFeasIntegral(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)));
2632  assert(!SCIPvarIsActive(var) || SCIPisFeasEQ(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)));
2633  assert(SCIPisFeasIntegral(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE)));
2634 
2635  /* collect local core information */
2636  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2637  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2638 
2639  SCIPdebugMsg(scip, "variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
2640  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2641  SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, demands[j]);
2642 
2643  /* check if the inference peak is part of the core */
2644  if( inferpeak < ect && lst <= inferpeak )
2645  {
2646  cands[ncands] = j;
2647  canddemands[ncands] = demands[j];
2648  ncands++;
2649 
2650  capacity -= demands[j];
2651  }
2652  }
2653 
2654  /* sort candidates indices w.r.t. their demands */
2655  SCIPsortDownIntInt(canddemands, cands, ncands);
2656 
2657  assert(capacity < 0);
2658  assert(ncands > 0);
2659 
2660  /* greedily remove candidates form the list such that the needed capacity is still exceeded */
2661  while( capacity + canddemands[ncands-1] < 0 )
2662  {
2663  ncands--;
2664  capacity += canddemands[ncands];
2665  assert(ncands > 0);
2666  }
2667 
2668  /* compute the size (number of time steps) of the job cores */
2669  for( c = 0; c < ncands; ++c )
2670  {
2671  var = vars[cands[c]];
2672  assert(var != NULL);
2673 
2674  duration = durations[cands[c]];
2675 
2676  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
2677  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2678 
2679  maxlst = MAX(maxlst, lst);
2680  minect = MIN(minect, ect);
2681  assert(maxlst < minect);
2682  }
2683 
2684  SCIPdebugMsg(scip, "infer peak %d, relaxed peak %d, lst %d, ect %d\n", inferpeak, relaxedpeak, maxlst, minect);
2685  assert(inferpeak >= maxlst);
2686  assert(inferpeak < minect);
2687 
2688  /* check if the collect variable are sufficient to prove the relaxed bound (relaxedpeak) */
2689  if( relaxedpeak < inferpeak )
2690  {
2691  inferpeak = MAX(maxlst, relaxedpeak);
2692  }
2693  else if( relaxedpeak > inferpeak )
2694  {
2695  inferpeak = MIN(minect-1, relaxedpeak);
2696  }
2697  assert(inferpeak >= hmin);
2698  assert(inferpeak < hmax);
2699  assert(inferpeak >= maxlst);
2700  assert(inferpeak < minect);
2701 
2702  /* post all necessary bound changes */
2703  for( c = 0; c < ncands; ++c )
2704  {
2705  var = vars[cands[c]];
2706  assert(var != NULL);
2707 
2708  if( usebdwidening )
2709  {
2710  duration = durations[cands[c]];
2711 
2712  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(inferpeak - duration + 1)) );
2713  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)inferpeak) );
2714  }
2715  else
2716  {
2717  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2718  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2719  }
2720 
2721  if( explanation != NULL )
2722  explanation[cands[c]] = TRUE;
2723  }
2724 
2725  SCIPfreeBufferArray(scip, &canddemands);
2726  SCIPfreeBufferArray(scip, &cands);
2727  }
2728 
2729  SCIPfreeBufferArray(scip, &reported);
2730 
2731  if( provedpeak != NULL )
2732  *provedpeak = inferpeak;
2733 
2734  return SCIP_OKAY;
2735 }
2736 
2737 #if 0
2738 /** repropagation of edge finding algorithm simplified version from Petr Vilim only a small subset is reported such that
2739  * energy in total and for bound change is enough
2740  */
2741 static
2742 SCIP_RETCODE resolvePropagationEdgeFinding(
2743  SCIP* scip, /**< SCIP data structure */
2744  int nvars, /**< number of start time variables (activities) */
2745  SCIP_VAR** vars, /**< array of start time variables */
2746  int* durations, /**< array of durations */
2747  int hmin, /**< left bound of time axis to be considered (including hmin) */
2748  int hmax, /**< right bound of time axis to be considered (not including hmax) */
2749  SCIP_VAR* infervar, /**< variable whose bound change is to be explained */
2750  INFERINFO inferinfo, /**< inference info containing position of correct bdchgids */
2751  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2752  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2753  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2754  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2755  )
2756 {
2757  int est;
2758  int lct;
2759  int j;
2760 
2761  /* ???????????????????? do bound widening */
2762 
2763  assert(scip != NULL);
2764  assert(nvars > 0);
2765  assert(inferInfoGetProprule(inferinfo) == PROPRULE_2_EDGEFINDING);
2766 
2767  SCIPdebugMsg(scip, "repropagate edge-finding with short reasons for variable <%s>\n", SCIPvarGetName(infervar));
2768 
2769  if( boundtype == SCIP_BOUNDTYPE_LOWER )
2770  {
2771  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
2772  }
2773  else
2774  {
2775  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
2776  }
2777 
2778  est = inferInfoGetData1(inferinfo);
2779  lct = inferInfoGetData2(inferinfo);
2780  assert(est < lct);
2781 
2782  /* collect the energies of all variables in [est_omega, lct_omega] */
2783  for( j = 0; j < nvars; ++j )
2784  {
2785  SCIP_VAR* var;
2786  SCIP_Bool left;
2787  SCIP_Bool right;
2788  int duration;
2789  int lb;
2790  int ub;
2791 
2792  var = vars[j];
2793  assert(var != NULL);
2794 
2795  if( var == infervar )
2796  {
2797  if( explanation != NULL )
2798  explanation[j] = TRUE;
2799 
2800  continue;
2801  }
2802 
2803  lb = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
2804  ub = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2805 
2806  duration = durations[j];
2807  assert(duration > 0);
2808 
2809  /* in case the earliest start time is equal to hmin we have to also consider the jobs which run in that region
2810  * since we use adjusted jobs during the propagation
2811  */
2812  left = (est == hmin && lb + duration > hmin) || lb >= est;
2813 
2814  /* in case the latest completion time is equal to hmax we have to also consider the jobs which run in that region
2815  * since we use adjusted jobs during the propagation
2816  */
2817  right = (lct == hmax && ub < hmax) || ub + duration <= lct;
2818 
2819  /* store all jobs running in [est_omega; lct_omega] */
2820  if( left && right )
2821  {
2822  /* check if bound widening should be used */
2823  if( usebdwidening )
2824  {
2825  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(lct - duration)) );
2826  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(est)) );
2827  }
2828  else
2829  {
2830  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
2831  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2832  }
2833 
2834  if( explanation != NULL )
2835  explanation[j] = TRUE;
2836  }
2837  }
2838 
2839  return SCIP_OKAY;
2840 }
2841 #endif
2842 
2843 /** compute the minimum overlaps w.r.t. the duration of the job and the time window [begin,end) */
2844 static
2845 int computeOverlap(
2846  int begin, /**< begin of the times interval */
2847  int end, /**< end of time interval */
2848  int est, /**< earliest start time */
2849  int lst, /**< latest start time */
2850  int duration /**< duration of the job */
2851  )
2852 {
2853  int left;
2854  int right;
2855  int ect;
2856  int lct;
2857 
2858  ect = est + duration;
2859  lct = lst + duration;
2860 
2861  /* check if job runs completely within [begin,end) */
2862  if( lct <= end && est >= begin )
2863  return duration;
2864 
2865  assert(lst <= end && ect >= begin);
2866 
2867  left = ect - begin;
2868  assert(left > 0);
2869 
2870  right = end - lst;
2871  assert(right > 0);
2872 
2873  return MIN3(left, right, end - begin);
2874 }
2875 
2876 /** an overload was detected due to the time-time edge-finding propagate; initialized conflict analysis, add an initial
2877  * reason
2878  *
2879  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
2880  */
2881 static
2883  SCIP* scip, /**< SCIP data structure */
2884  int nvars, /**< number of start time variables (activities) */
2885  SCIP_VAR** vars, /**< array of start time variables */
2886  int* durations, /**< array of durations */
2887  int* demands, /**< array of demands */
2888  int capacity, /**< capacity of the cumulative condition */
2889  int begin, /**< begin of the time window */
2890  int end, /**< end of the time window */
2891  SCIP_VAR* infervar, /**< variable which was propagate, or NULL */
2892  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
2893  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
2894  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
2895  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
2896  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
2897  )
2898 {
2899  int* locenergies;
2900  int* overlaps;
2901  int* idxs;
2902 
2903  SCIP_Longint requiredenergy;
2904  int v;
2905 
2906  SCIP_CALL( SCIPallocBufferArray(scip, &locenergies, nvars) );
2907  SCIP_CALL( SCIPallocBufferArray(scip, &overlaps, nvars) );
2908  SCIP_CALL( SCIPallocBufferArray(scip, &idxs, nvars) );
2909 
2910  /* energy which needs be explained */
2911  requiredenergy = ((SCIP_Longint) end - begin) * capacity;
2912 
2913  SCIPdebugMsg(scip, "analysis energy load in [%d,%d) (capacity %d, energy %" SCIP_LONGINT_FORMAT ")\n", begin, end, capacity, requiredenergy);
2914 
2915  /* collect global contribution and adjusted the required energy by the amount of energy the inference variable
2916  * takes
2917  */
2918  for( v = 0; v < nvars; ++v )
2919  {
2920  SCIP_VAR* var;
2921  int glbenergy;
2922  int duration;
2923  int demand;
2924  int est;
2925  int lst;
2926 
2927  var = vars[v];
2928  assert(var != NULL);
2929 
2930  locenergies[v] = 0;
2931  overlaps[v] = 0;
2932  idxs[v] = v;
2933 
2934  demand = demands[v];
2935  assert(demand > 0);
2936 
2937  duration = durations[v];
2938  assert(duration > 0);
2939 
2940  /* check if the variable equals the inference variable (the one which was propagated) */
2941  if( infervar == var )
2942  {
2943  int overlap;
2944  int right;
2945  int left;
2946 
2947  assert(relaxedbd != SCIP_UNKNOWN); /*lint !e777*/
2948 
2949  SCIPdebugMsg(scip, "inference variable <%s>[%g,%g] %s %g (duration %d, demand %d)\n",
2950  SCIPvarGetName(var), SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE),
2951  boundtype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", relaxedbd, duration, demand);
2952 
2953  /* compute the amount of energy which needs to be available for enforcing the propagation and report the bound
2954  * which is necessary from the inference variable
2955  */
2956  if( boundtype == SCIP_BOUNDTYPE_UPPER )
2957  {
2958  int lct;
2959 
2960  /* get the latest start time of the infer start time variable before the propagation took place */
2961  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
2962 
2963  /* the latest start time of the inference start time variable before the propagation needs to be smaller as
2964  * the end of the time interval; meaning the job needs be overlap with the time interval in case the job is
2965  * scheduled w.r.t. its latest start time
2966  */
2967  assert(lst < end);
2968 
2969  /* compute the overlap of the job in case it would be scheduled w.r.t. its latest start time and the time
2970  * interval (before the propagation)
2971  */
2972  right = MIN3(end - lst, end - begin, duration);
2973 
2974  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
2975  assert(right > 0);
2976 
2977  lct = SCIPconvertRealToInt(scip, relaxedbd) + duration;
2978  assert(begin <= lct);
2979  assert(bdchgidx == NULL || SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, TRUE)) < begin);
2980 
2981  /* compute the overlap of the job after the propagation but considering the relaxed bound */
2982  left = MIN(lct - begin + 1, end - begin);
2983  assert(left > 0);
2984 
2985  /* compute the minimum overlap; */
2986  overlap = MIN(left, right);
2987  assert(overlap > 0);
2988  assert(overlap <= end - begin);
2989  assert(overlap <= duration);
2990 
2991  if( usebdwidening )
2992  {
2993  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE)) <= (end - overlap));
2994  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)(end - overlap)) );
2995  }
2996  else
2997  {
2998  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
2999  }
3000  }
3001  else
3002  {
3003  int ect;
3004 
3005  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3006 
3007  /* get the earliest completion time of the infer start time variable before the propagation took place */
3008  ect = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) + duration;
3009 
3010  /* the earliest start time of the inference start time variable before the propagation needs to be larger as
3011  * than the beginning of the time interval; meaning the job needs be overlap with the time interval in case
3012  * the job is scheduled w.r.t. its earliest start time
3013  */
3014  assert(ect > begin);
3015 
3016  /* compute the overlap of the job in case it would be scheduled w.r.t. its earliest start time and the time
3017  * interval (before the propagation)
3018  */
3019  left = MIN3(ect - begin, end - begin, duration);
3020 
3021  /* the job needs to overlap with the interval; otherwise the propagation w.r.t. this time window is not valid */
3022  assert(left > 0);
3023 
3024  est = SCIPconvertRealToInt(scip, relaxedbd);
3025  assert(end >= est);
3026  assert(bdchgidx == NULL || end - SCIPgetVarLbAtIndex(scip, var, bdchgidx, TRUE) < duration);
3027 
3028  /* compute the overlap of the job after the propagation but considering the relaxed bound */
3029  right = MIN(end - est + 1, end - begin);
3030  assert(right > 0);
3031 
3032  /* compute the minimum overlap */
3033  overlap = MIN(left, right);
3034  assert(overlap > 0);
3035  assert(overlap <= end - begin);
3036  assert(overlap <= duration);
3037 
3038  if( usebdwidening )
3039  {
3040  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE)) >= (begin + overlap - duration));
3041  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)(begin + overlap - duration)) );
3042  }
3043  else
3044  {
3045  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
3046  }
3047  }
3048 
3049  /* subtract the amount of energy which is available due to the overlap of the inference start time */
3050  requiredenergy -= (SCIP_Longint) overlap * demand;
3051 
3052  if( explanation != NULL )
3053  explanation[v] = TRUE;
3054 
3055  continue;
3056  }
3057 
3058  /* global time points */
3059  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
3060  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
3061 
3062  glbenergy = 0;
3063 
3064  /* check if the has any overlap w.r.t. global bound; meaning some parts of the job will run for sure within the
3065  * time window
3066  */
3067  if( est + duration > begin && lst < end )
3068  {
3069  /* evaluated global contribution */
3070  glbenergy = computeOverlap(begin, end, est, lst, duration) * demand;
3071 
3072  /* remove the globally available energy form the required energy */
3073  requiredenergy -= glbenergy;
3074 
3075  if( explanation != NULL )
3076  explanation[v] = TRUE;
3077  }
3078 
3079  /* local time points */
3080  est = SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, var, bdchgidx, FALSE));
3081  lst = SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, var, bdchgidx, FALSE));
3082 
3083  /* check if the job has any overlap w.r.t. local bound; meaning some parts of the job will run for sure within the
3084  * time window
3085  */
3086  if( est + duration > begin && lst < end )
3087  {
3088  overlaps[v] = computeOverlap(begin, end, est, lst, duration);
3089 
3090  /* evaluated additionally local energy contribution */
3091  locenergies[v] = overlaps[v] * demand - glbenergy;
3092  assert(locenergies[v] >= 0);
3093  }
3094  }
3095 
3096  /* sort the variable contributions w.r.t. additional local energy contributions */
3097  SCIPsortDownIntIntInt(locenergies, overlaps, idxs, nvars);
3098 
3099  /* add local energy contributions until an overload is implied */
3100  for( v = 0; v < nvars && requiredenergy >= 0; ++v )
3101  {
3102  SCIP_VAR* var;
3103  int duration;
3104  int overlap;
3105  int relaxlb;
3106  int relaxub;
3107  int idx;
3108 
3109  idx = idxs[v];
3110  assert(idx >= 0 && idx < nvars);
3111 
3112  var = vars[idx];
3113  assert(var != NULL);
3114  assert(var != infervar);
3115 
3116  duration = durations[idx];
3117  assert(duration > 0);
3118 
3119  overlap = overlaps[v];
3120  assert(overlap > 0);
3121 
3122  requiredenergy -= locenergies[v];
3123 
3124  if( requiredenergy < -1 )
3125  {
3126  int demand;
3127 
3128  demand = demands[idx];
3129  assert(demand > 0);
3130 
3131  overlap += (int)((requiredenergy + 1) / demand);
3132 
3133 #ifndef NDEBUG
3134  requiredenergy += locenergies[v];
3135  requiredenergy -= (SCIP_Longint) overlap * demand;
3136  assert(requiredenergy < 0);
3137 #endif
3138  }
3139  assert(overlap > 0);
3140 
3141  relaxlb = begin - duration + overlap;
3142  relaxub = end - overlap;
3143 
3144  SCIPdebugMsg(scip, "variable <%s> glb=[%g,%g] loc=[%g,%g], conf=[%g,%g], added=[%d,%d] (demand %d, duration %d)\n",
3145  SCIPvarGetName(var),
3148  SCIPgetConflictVarLb(scip, var), SCIPgetConflictVarUb(scip, var),
3149  relaxlb, relaxub, demands[idx], duration);
3150 
3151  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, var, bdchgidx, (SCIP_Real)relaxlb) );
3152  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, var, bdchgidx, (SCIP_Real)relaxub) );
3153 
3154  if( explanation != NULL )
3155  explanation[idx] = TRUE;
3156  }
3157 
3158  assert(requiredenergy < 0);
3159 
3160  SCIPfreeBufferArray(scip, &idxs);
3161  SCIPfreeBufferArray(scip, &overlaps);
3162  SCIPfreeBufferArray(scip, &locenergies);
3163 
3164  return SCIP_OKAY;
3165 }
3166 
3167 /** resolve propagation w.r.t. the cumulative condition */
3168 static
3170  SCIP* scip, /**< SCIP data structure */
3171  int nvars, /**< number of start time variables (activities) */
3172  SCIP_VAR** vars, /**< array of start time variables */
3173  int* durations, /**< array of durations */
3174  int* demands, /**< array of demands */
3175  int capacity, /**< cumulative capacity */
3176  int hmin, /**< left bound of time axis to be considered (including hmin) */
3177  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3178  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
3179  INFERINFO inferinfo, /**< the user information */
3180  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
3181  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
3182  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
3183  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3184  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3185  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3186  )
3187 {
3188  switch( inferInfoGetProprule(inferinfo) )
3189  {
3190  case PROPRULE_1_CORETIMES:
3191  {
3192  int inferdemand;
3193  int inferduration;
3194  int inferpos;
3195  int inferpeak;
3196  int relaxedpeak;
3197  int provedpeak;
3198 
3199  /* get the position of the inferred variable in the vars array */
3200  inferpos = inferInfoGetData1(inferinfo);
3201  if( inferpos >= nvars || vars[inferpos] != infervar )
3202  {
3203  /* find inference variable in constraint */
3204  for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
3205  {}
3206  }
3207  assert(inferpos < nvars);
3208  assert(vars[inferpos] == infervar);
3209 
3210  inferdemand = demands[inferpos];
3211  inferduration = durations[inferpos];
3212 
3213  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3214  {
3215  /* we propagated the latest start time (upper bound) step wise with a step length of at most the duration of
3216  * the inference variable
3217  */
3218  assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE) - SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < inferduration + 0.5);
3219 
3220  SCIPdebugMsg(scip, "variable <%s>: upper bound changed from %g to %g (relaxed %g)\n",
3221  SCIPvarGetName(infervar), SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, FALSE),
3222  SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3223 
3224  /* get the inference peak that the time point which lead to the that propagtion */
3225  inferpeak = inferInfoGetData2(inferinfo);
3226  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3227  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3228  */
3229  assert(SCIPconvertRealToInt(scip, SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE)) + inferduration <= inferpeak);
3230  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) + inferduration;
3231 
3232  /* make sure that the relaxed peak is part of the effective horizon */
3233  relaxedpeak = MIN(relaxedpeak, hmax-1);
3234 
3235  /* make sure that relaxed peak is not larger than the infer peak
3236  *
3237  * This can happen in case the variable is not an active variable!
3238  */
3239  relaxedpeak = MAX(relaxedpeak, inferpeak);
3240  assert(relaxedpeak >= inferpeak);
3241  assert(relaxedpeak >= hmin);
3242  }
3243  else
3244  {
3245  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3246 
3247  SCIPdebugMsg(scip, "variable <%s>: lower bound changed from %g to %g (relaxed %g)\n",
3248  SCIPvarGetName(infervar), SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, FALSE),
3249  SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE), relaxedbd);
3250 
3251  /* get the time interval where the job could not be scheduled */
3252  inferpeak = inferInfoGetData2(inferinfo);
3253  /* the bound passed back to be resolved might be tighter as the bound propagted by the core time propagator;
3254  * this can happen if the variable is not activ and aggregated to an activ variable with a scale != 1.0
3255  */
3256  assert(SCIPconvertRealToInt(scip, SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE)) - 1 >= inferpeak);
3257  relaxedpeak = SCIPconvertRealToInt(scip, relaxedbd) - 1;
3258 
3259  /* make sure that the relaxed peak is part of the effective horizon */
3260  relaxedpeak = MAX(relaxedpeak, hmin);
3261 
3262  /* make sure that relaxed peak is not larger than the infer peak
3263  *
3264  * This can happen in case the variable is not an active variable!
3265  */
3266  relaxedpeak = MIN(relaxedpeak, inferpeak);
3267  assert(relaxedpeak < hmax);
3268  }
3269 
3270  /* resolves the propagation of the core time algorithm */
3271  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3272  infervar, inferdemand, inferpeak, relaxedpeak, bdchgidx, usebdwidening, &provedpeak, explanation) );
3273 
3274  if( boundtype == SCIP_BOUNDTYPE_UPPER )
3275  {
3276  if( usebdwidening )
3277  {
3278  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)provedpeak) );
3279  }
3280  else
3281  {
3282  /* old upper bound of variable itself is part of the explanation */
3283  SCIP_CALL( SCIPaddConflictUb(scip, infervar, bdchgidx) );
3284  }
3285  }
3286  else
3287  {
3288  assert(boundtype == SCIP_BOUNDTYPE_LOWER);
3289 
3290  if( usebdwidening )
3291  {
3292  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, bdchgidx, (SCIP_Real)(provedpeak - inferduration + 1)) );
3293  }
3294  else
3295  {
3296  /* old lower bound of variable itself is part of the explanation */
3297  SCIP_CALL( SCIPaddConflictLb(scip, infervar, bdchgidx) );
3298  }
3299  }
3300 
3301  if( explanation != NULL )
3302  explanation[inferpos] = TRUE;
3303 
3304  break;
3305  }
3307  case PROPRULE_3_TTEF:
3308  {
3309  int begin;
3310  int end;
3311 
3312  begin = inferInfoGetData1(inferinfo);
3313  end = inferInfoGetData2(inferinfo);
3314  assert(begin < end);
3315 
3316  begin = MAX(begin, hmin);
3317  end = MIN(end, hmax);
3318 
3319  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
3320  begin, end, infervar, boundtype, bdchgidx, relaxedbd, usebdwidening, explanation) );
3321 
3322  break;
3323  }
3324 
3325  case PROPRULE_0_INVALID:
3326  default:
3327  SCIPerrorMessage("invalid inference information %d\n", inferInfoGetProprule(inferinfo));
3328  SCIPABORT();
3329  return SCIP_INVALIDDATA; /*lint !e527*/
3330  }
3331 
3332  (*result) = SCIP_SUCCESS;
3333 
3334  return SCIP_OKAY;
3335 }
3336 
3337 /**@} */
3338 
3339 
3340 /**@name Enforcement methods
3341  *
3342  * @{
3343  */
3344 
3345 /** apply all fixings which are given by the alternative bounds */
3346 static
3348  SCIP* scip, /**< SCIP data structure */
3349  SCIP_VAR** vars, /**< array of active variables */
3350  int nvars, /**< number of active variables */
3351  int* alternativelbs, /**< alternative lower bounds */
3352  int* alternativeubs, /**< alternative lower bounds */
3353  int* downlocks, /**< number of constraints with down lock participating by the computation */
3354  int* uplocks, /**< number of constraints with up lock participating by the computation */
3355  SCIP_Bool* branched /**< pointer to store if a branching was applied */
3356  )
3357 {
3358  int v;
3359 
3360  for( v = 0; v < nvars; ++v )
3361  {
3362  SCIP_VAR* var;
3363  SCIP_Real objval;
3364 
3365  var = vars[v];
3366  assert(var != NULL);
3367 
3368  objval = SCIPvarGetObj(var);
3369 
3370  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] && !SCIPisNegative(scip, objval) )
3371  {
3372  int ub;
3373 
3374  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3375 
3376  if( alternativelbs[v] <= ub )
3377  {
3378  SCIP_CALL( SCIPbranchVarHole(scip, var, SCIPvarGetLbLocal(var), (SCIP_Real)alternativelbs[v], NULL, NULL) );
3379  (*branched) = TRUE;
3380 
3381  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%g,%d)\n", SCIPvarGetName(var),
3382  SCIPvarGetLbLocal(var), alternativelbs[v]);
3383 
3384  return SCIP_OKAY;
3385  }
3386  }
3387 
3388  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] && !SCIPisPositive(scip, objval) )
3389  {
3390  int lb;
3391 
3392  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3393 
3394  if( alternativeubs[v] >= lb )
3395  {
3396  SCIP_CALL( SCIPbranchVarHole(scip, var, (SCIP_Real)alternativeubs[v], SCIPvarGetUbLocal(var), NULL, NULL) );
3397  (*branched) = TRUE;
3398 
3399  SCIPdebugMsg(scip, "variable <%s> branched domain hole (%d,%g)\n", SCIPvarGetName(var),
3400  alternativeubs[v], SCIPvarGetUbLocal(var));
3401 
3402  return SCIP_OKAY;
3403  }
3404  }
3405  }
3406 
3407  return SCIP_OKAY;
3408 }
3409 
3410 /** remove the capacity requirments for all job which start at the curtime */
3411 static
3413  SCIP_CONSDATA* consdata, /**< constraint data */
3414  int curtime, /**< current point in time */
3415  int* starttimes, /**< array of start times */
3416  int* startindices, /**< permutation with respect to the start times */
3417  int* freecapacity, /**< pointer to store the resulting free capacity */
3418  int* idx, /**< pointer to index in start time array */
3419  int nvars /**< number of vars in array of starttimes and startindices */
3420  )
3421 {
3422 #if defined SCIP_DEBUG && !defined NDEBUG
3423  int oldidx;
3424 
3425  assert(idx != NULL);
3426  oldidx = *idx;
3427 #else
3428  assert(idx != NULL);
3429 #endif
3430 
3431  assert(starttimes != NULL);
3432  assert(starttimes != NULL);
3433  assert(freecapacity != NULL);
3434  assert(starttimes[*idx] == curtime);
3435  assert(consdata->demands != NULL);
3436  assert(freecapacity != idx);
3437 
3438  /* subtract all capacity needed up to this point */
3439  (*freecapacity) -= consdata->demands[startindices[*idx]];
3440 
3441  while( (*idx)+1 < nvars && starttimes[(*idx)+1] == curtime )
3442  {
3443  ++(*idx);
3444  (*freecapacity) -= consdata->demands[startindices[(*idx)]];
3445  assert(freecapacity != idx);
3446  }
3447 #ifdef SCIP_DEBUG
3448  assert(oldidx <= *idx);
3449 #endif
3450 }
3451 
3452 /** add the capacity requirments for all job which end at the curtime */
3453 static
3454 void addEndingJobDemands(
3455  SCIP_CONSDATA* consdata, /**< constraint data */
3456  int curtime, /**< current point in time */
3457  int* endtimes, /**< array of end times */
3458  int* endindices, /**< permutation with rspect to the end times */
3459  int* freecapacity, /**< pointer to store the resulting free capacity */
3460  int* idx, /**< pointer to index in end time array */
3461  int nvars /**< number of vars in array of starttimes and startindices */
3462  )
3463 {
3464 #if defined SCIP_DEBUG && !defined NDEBUG
3465  int oldidx;
3466  oldidx = *idx;
3467 #endif
3468 
3469  /* free all capacity usages of jobs the are no longer running */
3470  while( endtimes[*idx] <= curtime && *idx < nvars)
3471  {
3472  (*freecapacity) += consdata->demands[endindices[*idx]];
3473  ++(*idx);
3474  }
3475 
3476 #ifdef SCIP_DEBUG
3477  assert(oldidx <= *idx);
3478 #endif
3479 }
3480 
3481 /** computes a point in time when the capacity is exceeded returns hmax if this does not happen */
3482 static
3484  SCIP* scip, /**< SCIP data structure */
3485  SCIP_CONSDATA* consdata, /**< constraint handler data */
3486  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3487  int* timepoint /**< pointer to store the time point of the peak */
3488  )
3489 {
3490  int* starttimes; /* stores when each job is starting */
3491  int* endtimes; /* stores when each job ends */
3492  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
3493  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
3494 
3495  int nvars; /* number of activities for this constraint */
3496  int freecapacity; /* remaining capacity */
3497  int curtime; /* point in time which we are just checking */
3498  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
3499 
3500  int hmin;
3501  int hmax;
3502 
3503  int j;
3504 
3505  assert(consdata != NULL);
3506 
3507  nvars = consdata->nvars;
3508  assert(nvars > 0);
3509 
3510  *timepoint = consdata->hmax;
3511 
3512  assert(consdata->vars != NULL);
3513 
3514  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
3515  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
3516  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
3517  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
3518 
3519  /* create event point arrays */
3520  createSortedEventpointsSol(scip, sol, consdata->nvars, consdata->vars, consdata->durations,
3521  starttimes, endtimes, startindices, endindices);
3522 
3523  endindex = 0;
3524  freecapacity = consdata->capacity;
3525  hmin = consdata->hmin;
3526  hmax = consdata->hmax;
3527 
3528  /* check each startpoint of a job whether the capacity is kept or not */
3529  for( j = 0; j < nvars; ++j )
3530  {
3531  curtime = starttimes[j];
3532  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
3533 
3534  if( curtime >= hmax )
3535  break;
3536 
3537  /* remove the capacity requirments for all job which start at the curtime */
3538  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
3539 
3540  /* add the capacity requirments for all job which end at the curtime */
3541  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
3542 
3543  assert(freecapacity <= consdata->capacity);
3544  assert(endindex <= nvars);
3545 
3546  /* endindex - points to the next job which will finish */
3547  /* j - points to the last job that has been released */
3548 
3549  /* if free capacity is smaller than zero, then add branching candidates */
3550  if( freecapacity < 0 && curtime >= hmin )
3551  {
3552  *timepoint = curtime;
3553  break;
3554  }
3555  } /*lint --e{850}*/
3556 
3557  /* free all buffer arrays */
3558  SCIPfreeBufferArray(scip, &endindices);
3559  SCIPfreeBufferArray(scip, &startindices);
3560  SCIPfreeBufferArray(scip, &endtimes);
3561  SCIPfreeBufferArray(scip, &starttimes);
3562 
3563  return SCIP_OKAY;
3564 }
3565 
3566 /** checks all cumulative constraints for infeasibility and add branching candidates to storage */
3567 static
3569  SCIP* scip, /**< SCIP data structure */
3570  SCIP_CONS** conss, /**< constraints to be processed */
3571  int nconss, /**< number of constraints */
3572  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
3573  int* nbranchcands /**< pointer to store the number of branching variables */
3574  )
3575 {
3576  SCIP_HASHTABLE* collectedvars;
3577  int c;
3578 
3579  assert(scip != NULL);
3580  assert(conss != NULL);
3581 
3582  /* create a hash table */
3583  SCIP_CALL( SCIPhashtableCreate(&collectedvars, SCIPblkmem(scip), SCIPgetNVars(scip),
3584  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3585 
3586  assert(scip != NULL);
3587  assert(conss != NULL);
3588 
3589  for( c = 0; c < nconss; ++c )
3590  {
3591  SCIP_CONS* cons;
3592  SCIP_CONSDATA* consdata;
3593 
3594  int curtime;
3595  int j;
3596 
3597  cons = conss[c];
3598  assert(cons != NULL);
3599 
3600  if( !SCIPconsIsActive(cons) )
3601  continue;
3602 
3603  consdata = SCIPconsGetData(cons);
3604  assert(consdata != NULL);
3605 
3606  /* get point in time when capacity is exceeded */
3607  SCIP_CALL( computePeak(scip, consdata, sol, &curtime) );
3608 
3609  if( curtime < consdata->hmin || curtime >= consdata->hmax )
3610  continue;
3611 
3612  /* report all variables that are running at that point in time */
3613  for( j = 0; j < consdata->nvars; ++j )
3614  {
3615  SCIP_VAR* var;
3616  int lb;
3617  int ub;
3618 
3619  var = consdata->vars[j];
3620  assert(var != NULL);
3621 
3622  /* check if the variable was already added */
3623  if( SCIPhashtableExists(collectedvars, (void*)var) )
3624  continue;
3625 
3626  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
3627  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
3628 
3629  if( lb <= curtime && ub + consdata->durations[j] > curtime && lb < ub )
3630  {
3631  SCIP_Real solval;
3632  SCIP_Real score;
3633 
3634  solval = SCIPgetSolVal(scip, sol, var);
3635  score = MIN(solval - lb, ub - solval) / ((SCIP_Real)ub-lb);
3636 
3637  SCIPdebugMsg(scip, "add var <%s> to branch cand storage\n", SCIPvarGetName(var));
3638  SCIP_CALL( SCIPaddExternBranchCand(scip, var, score, lb + (ub - lb) / 2.0 + 0.2) );
3639  (*nbranchcands)++;
3640 
3641  SCIP_CALL( SCIPhashtableInsert(collectedvars, var) );
3642  }
3643  }
3644  }
3645 
3646  SCIPhashtableFree(&collectedvars);
3647 
3648  SCIPdebugMsg(scip, "found %d branching candidates\n", *nbranchcands);
3649 
3650  return SCIP_OKAY;
3651 }
3652 
3653 /** enforcement of an LP, pseudo, or relaxation solution */
3654 static
3656  SCIP* scip, /**< SCIP data structure */
3657  SCIP_CONS** conss, /**< constraints to be processed */
3658  int nconss, /**< number of constraints */
3659  SCIP_SOL* sol, /**< solution to enforce (NULL for LP or pseudo solution) */
3660  SCIP_Bool branch, /**< should branching candidates be collected */
3661  SCIP_RESULT* result /**< pointer to store the result */
3662  )
3663 {
3664  if( branch )
3665  {
3666  int nbranchcands;
3667 
3668  nbranchcands = 0;
3669  SCIP_CALL( collectBranchingCands(scip, conss, nconss, sol, &nbranchcands) );
3670 
3671  if( nbranchcands > 0 )
3672  (*result) = SCIP_INFEASIBLE;
3673  }
3674  else
3675  {
3676  SCIP_Bool violated;
3677  int c;
3678 
3679  violated = FALSE;
3680 
3681  /* first check if a constraints is violated */
3682  for( c = 0; c < nconss && !violated; ++c )
3683  {
3684  SCIP_CONS* cons;
3685 
3686  cons = conss[c];
3687  assert(cons != NULL);
3688 
3689  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
3690  }
3691 
3692  if( violated )
3693  (*result) = SCIP_INFEASIBLE;
3694  }
3695 
3696  return SCIP_OKAY;
3697 }
3698 
3699 /**@} */
3700 
3701 /**@name Propagation
3702  *
3703  * @{
3704  */
3705 
3706 /** check if cumulative constraint is independently of all other constraints */
3707 static
3709  SCIP_CONS* cons /**< cumulative constraint */
3710  )
3711 {
3712  SCIP_CONSDATA* consdata;
3713  SCIP_VAR** vars;
3714  SCIP_Bool* downlocks;
3715  SCIP_Bool* uplocks;
3716  int nvars;
3717  int v;
3718 
3719  consdata = SCIPconsGetData(cons);
3720  assert(consdata != NULL);
3721 
3722  nvars = consdata->nvars;
3723  vars = consdata->vars;
3724  downlocks = consdata->downlocks;
3725  uplocks = consdata->uplocks;
3726 
3727  /* check if the cumulative constraint has the only locks on the involved variables */
3728  for( v = 0; v < nvars; ++v )
3729  {
3730  SCIP_VAR* var;
3731 
3732  var = vars[v];
3733  assert(var != NULL);
3734 
3735  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)downlocks[v]
3736  || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)uplocks[v] )
3737  return FALSE;
3738  }
3739 
3740  return TRUE;
3741 }
3742 
3743 /** in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the fixings
3744  * (dual reductions)
3745  */
3746 static
3748  SCIP* scip, /**< SCIP data structure */
3749  SCIP_CONS* cons, /**< cumulative constraint */
3750  SCIP_Longint maxnodes, /**< number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit) */
3751  int* nchgbds, /**< pointer to store the number changed variable bounds */
3752  int* nfixedvars, /**< pointer to count number of fixings */
3753  int* ndelconss, /**< pointer to count number of deleted constraints */
3754  SCIP_Bool* cutoff, /**< pointer to store if the constraint is infeasible */
3755  SCIP_Bool* unbounded /**< pointer to store if the constraint is unbounded */
3756  )
3757 {
3758  SCIP_CONSDATA* consdata;
3759  SCIP_VAR** vars;
3760  SCIP_Real* objvals;
3761  SCIP_Real* lbs;
3762  SCIP_Real* ubs;
3763  SCIP_Real timelimit;
3764  SCIP_Real memorylimit;
3765  SCIP_Bool solved;
3766  SCIP_Bool error;
3767 
3768  int ncheckconss;
3769  int nvars;
3770  int v;
3771 
3772  assert(scip != NULL);
3773  assert(!SCIPconsIsModifiable(cons));
3774  assert(SCIPgetNConss(scip) > 0);
3775 
3776  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
3777  * would/could end in an implication which can lead to cutoff of the/all optimal solution
3778  */
3779  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
3780  return SCIP_OKAY;
3781 
3782  /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
3783  * use the locks to decide for a dual reduction using this constraint;
3784  */
3785  if( !SCIPconsIsChecked(cons) )
3786  return SCIP_OKAY;
3787 
3788  ncheckconss = SCIPgetNCheckConss(scip);
3789 
3790  /* if the cumulative constraint is the only constraint of the original problem or the only check constraint in the
3791  * presolved problem do nothing execpt to change the parameter settings
3792  */
3793  if( ncheckconss == 1 )
3794  {
3795  /* shrink the minimal maximum value for the conflict length */
3796  SCIP_CALL( SCIPsetIntParam(scip, "conflict/minmaxvars", 10) );
3797 
3798  /* use only first unique implication point */
3799  SCIP_CALL( SCIPsetIntParam(scip, "conflict/fuiplevels", 1) );
3800 
3801  /* do not use reconversion conflicts */
3802  SCIP_CALL( SCIPsetIntParam(scip, "conflict/reconvlevels", 0) );
3803 
3804  /* after 250 conflict we force a restart since then the variable statistics are reasonable initialized */
3805  SCIP_CALL( SCIPsetIntParam(scip, "conflict/restartnum", 250) );
3806 
3807  /* increase the number of conflicts which induce a restart */
3808  SCIP_CALL( SCIPsetRealParam(scip, "conflict/restartfac", 2.0) );
3809 
3810  /* weight the variable which made into a conflict */
3811  SCIP_CALL( SCIPsetRealParam(scip, "conflict/conflictweight", 1.0) );
3812 
3813  /* do not check pseudo solution (for performance reasons) */
3814  SCIP_CALL( SCIPsetBoolParam(scip, "constraints/disableenfops", TRUE) );
3815 
3816  /* use value based history to detect a reasonable branching point */
3817  SCIP_CALL( SCIPsetBoolParam(scip, "history/valuebased", TRUE) );
3818 
3819  /* turn of LP relaxation */
3820  SCIP_CALL( SCIPsetIntParam(scip, "lp/solvefreq", -1) );
3821 
3822  /* prefer the down branch in case the value based history does not suggest something */
3823  SCIP_CALL( SCIPsetCharParam(scip, "nodeselection/childsel", 'd') );
3824 
3825  /* accept any bound change */
3826  SCIP_CALL( SCIPsetRealParam(scip, "numerics/boundstreps", 1e-6) );
3827 
3828  /* allow for at most 10 restart, after that the value based history should be reliable */
3829  SCIP_CALL( SCIPsetIntParam(scip, "presolving/maxrestarts", 10) );
3830 
3831  /* set priority for depth first search to highest possible value */
3832  SCIP_CALL( SCIPsetIntParam(scip, "nodeselection/dfs/stdpriority", INT_MAX/4) );
3833 
3834  return SCIP_OKAY;
3835  }
3836 
3837  consdata = SCIPconsGetData(cons);
3838  assert(consdata != NULL);
3839 
3840  /* check if already tried to solve that constraint as independent sub problem; we do not want to try it again if we
3841  * fail on the first place
3842  */
3843  if( consdata->triedsolving )
3844  return SCIP_OKAY;
3845 
3846  /* check if constraint is independently */
3847  if( !isConsIndependently(cons) )
3848  return SCIP_OKAY;
3849 
3850  /* mark the constraint to be tried of solving it as independent sub problem; in case that is successful the
3851  * constraint is deleted; otherwise, we want to ensure that we do not try that again
3852  */
3853  consdata->triedsolving = TRUE;
3854 
3855  SCIPdebugMsg(scip, "the cumulative constraint <%s> is independent from rest of the problem (%d variables, %d constraints)\n",
3856  SCIPconsGetName(cons), SCIPgetNVars(scip), SCIPgetNConss(scip));
3857  SCIPdebugPrintCons(scip, cons, NULL);
3858 
3859  nvars = consdata->nvars;
3860  vars = consdata->vars;
3861 
3862  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
3863  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
3864  SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
3865 
3866  for( v = 0; v < nvars; ++v )
3867  {
3868  SCIP_VAR* var;
3869 
3870  /* if a variables array is given, use the variable bounds otherwise the default values stored in the ests and lsts
3871  * array
3872  */
3873  var = vars[v];
3874  assert(var != NULL);
3875 
3876  lbs[v] = SCIPvarGetLbLocal(var);
3877  ubs[v] = SCIPvarGetUbLocal(var);
3878 
3879  objvals[v] = SCIPvarGetObj(var);
3880  }
3881 
3882  /* check whether there is enough time and memory left */
3883  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
3884  if( !SCIPisInfinity(scip, timelimit) )
3885  timelimit -= SCIPgetSolvingTime(scip);
3886  SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) );
3887 
3888  /* substract the memory already used by the main SCIP and the estimated memory usage of external software */
3889  if( !SCIPisInfinity(scip, memorylimit) )
3890  {
3891  memorylimit -= SCIPgetMemUsed(scip)/1048576.0;
3892  memorylimit -= SCIPgetMemExternEstim(scip)/1048576.0;
3893  }
3894 
3895  /* solve the cumulative condition separately */
3896  SCIP_CALL( SCIPsolveCumulative(scip, nvars, lbs, ubs, objvals, consdata->durations, consdata->demands, consdata->capacity,
3897  consdata->hmin, consdata->hmax, timelimit, memorylimit, maxnodes, &solved, cutoff, unbounded, &error) );
3898 
3899  if( !(*cutoff) && !(*unbounded) && !error )
3900  {
3901  SCIP_Bool infeasible;
3902  SCIP_Bool tightened;
3903  SCIP_Bool allfixed;
3904 
3905  allfixed = TRUE;
3906 
3907  for( v = 0; v < nvars; ++v )
3908  {
3909  /* check if variable is fixed */
3910  if( lbs[v] + 0.5 > ubs[v] )
3911  {
3912  SCIP_CALL( SCIPfixVar(scip, vars[v], lbs[v], &infeasible, &tightened) );
3913  assert(!infeasible);
3914 
3915  if( tightened )
3916  {
3917  (*nfixedvars)++;
3918  consdata->triedsolving = FALSE;
3919  }
3920  }
3921  else
3922  {
3923  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], lbs[v], TRUE, &infeasible, &tightened) );
3924  assert(!infeasible);
3925 
3926  if( tightened )
3927  {
3928  (*nchgbds)++;
3929  consdata->triedsolving = FALSE;
3930  }
3931 
3932  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], ubs[v], TRUE, &infeasible, &tightened) );
3933  assert(!infeasible);
3934 
3935  if( tightened )
3936  {
3937  (*nchgbds)++;
3938  consdata->triedsolving = FALSE;
3939  }
3940 
3941  allfixed = FALSE;
3942  }
3943  }
3944 
3945  /* if all variables are fixed, remove the cumulative constraint since it is redundant */
3946  if( allfixed )
3947  {
3948  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3949  (*ndelconss)++;
3950  }
3951  }
3952 
3953  SCIPfreeBufferArray(scip, &objvals);
3954  SCIPfreeBufferArray(scip, &ubs);
3955  SCIPfreeBufferArray(scip, &lbs);
3956 
3957  return SCIP_OKAY;
3958 }
3959 
3960 /** start conflict analysis to analysis the core insertion which is infeasible */
3961 static
3963  SCIP* scip, /**< SCIP data structure */
3964  int nvars, /**< number of start time variables (activities) */
3965  SCIP_VAR** vars, /**< array of start time variables */
3966  int* durations, /**< array of durations */
3967  int* demands, /**< array of demands */
3968  int capacity, /**< cumulative capacity */
3969  int hmin, /**< left bound of time axis to be considered (including hmin) */
3970  int hmax, /**< right bound of time axis to be considered (not including hmax) */
3971  SCIP_VAR* infervar, /**< start time variable which lead to the infeasibilty */
3972  int inferduration, /**< duration of the start time variable */
3973  int inferdemand, /**< demand of the start time variable */
3974  int inferpeak, /**< profile preak which causes the infeasibilty */
3975  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
3976  SCIP_Bool* initialized, /**< pointer to store if the conflict analysis was initialized */
3977  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
3978  )
3979 {
3980  SCIPdebugMsg(scip, "detected infeasibility due to adding a core to the core resource profile\n");
3981  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (demand %d, duration %d)\n", SCIPvarGetName(infervar),
3982  SCIPvarGetLbLocal(infervar), SCIPvarGetUbLocal(infervar), inferdemand, inferduration);
3983 
3984  /* initialize conflict analysis if conflict analysis is applicable */
3986  {
3988 
3989  SCIP_CALL( resolvePropagationCoretimes(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
3990  infervar, inferdemand, inferpeak, inferpeak, NULL, usebdwidening, NULL, explanation) );
3991 
3992  SCIPdebugMsg(scip, "add lower and upper bounds of variable <%s>\n", SCIPvarGetName(infervar));
3993 
3994  /* add both bound of the inference variable since these biuld the core which we could not inserted */
3995  if( usebdwidening )
3996  {
3997  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, infervar, NULL, (SCIP_Real)(inferpeak - inferduration + 1)) );
3998  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, infervar, NULL, (SCIP_Real)inferpeak) );
3999  }
4000  else
4001  {
4002  SCIP_CALL( SCIPaddConflictLb(scip, infervar, NULL) );
4003  SCIP_CALL( SCIPaddConflictUb(scip, infervar, NULL) );
4004  }
4005 
4006  *initialized = TRUE;
4007  }
4008 
4009  return SCIP_OKAY;
4010 }
4011 
4012 /** We are using the core resource profile which contains all core except the one of the start time variable which we
4013  * want to propagate, to incease the earliest start time. This we are doing in steps of length at most the duration of
4014  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4015  * analysis
4016  */
4017 static
4019  SCIP* scip, /**< SCIP data structure */
4020  int nvars, /**< number of start time variables (activities) */
4021  SCIP_VAR** vars, /**< array of start time variables */
4022  int* durations, /**< array of durations */
4023  int* demands, /**< array of demands */
4024  int capacity, /**< cumulative capacity */
4025  int hmin, /**< left bound of time axis to be considered (including hmin) */
4026  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4027  SCIP_CONS* cons, /**< constraint which is propagated */
4028  SCIP_PROFILE* profile, /**< resource profile */
4029  int idx, /**< position of the variable to propagate */
4030  int* nchgbds, /**< pointer to store the number of bound changes */
4031  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
4032  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4033  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4034  SCIP_Bool* infeasible /**< pointer to store if the constraint is infeasible */
4035  )
4036 {
4037  SCIP_VAR* var;
4038  int ntimepoints;
4039  int duration;
4040  int demand;
4041  int peak;
4042  int newlb;
4043  int est;
4044  int lst;
4045  int pos;
4046 
4047  var = vars[idx];
4048  assert(var != NULL);
4049 
4050  duration = durations[idx];
4051  assert(duration > 0);
4052 
4053  demand = demands[idx];
4054  assert(demand > 0);
4055 
4056  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4057  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4058  ntimepoints = SCIPprofileGetNTimepoints(profile);
4059 
4060  /* first we find left position of earliest start time (lower bound) in resource profile; this position gives us the
4061  * load which we have at the earliest start time (lower bound)
4062  */
4063  (void) SCIPprofileFindLeft(profile, est, &pos);
4064 
4065  SCIPdebugMsg(scip, "propagate earliest start time (lower bound) (pos %d)\n", pos);
4066 
4067  /* we now trying to move the earliest start time in steps of at most "duration" length */
4068  do
4069  {
4070  INFERINFO inferinfo;
4071  SCIP_Bool tightened;
4072  int ect;
4073 
4074 #ifndef NDEBUG
4075  {
4076  /* in debug mode we check that we adjust the search position correctly */
4077  int tmppos;
4078 
4079  (void)SCIPprofileFindLeft(profile, est, &tmppos);
4080  assert(pos == tmppos);
4081  }
4082 #endif
4083  ect = est + duration;
4084  peak = -1;
4085 
4086  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4087  * want a peak which is closest to the earliest completion time
4088  */
4089  do
4090  {
4091  /* check if the profile load conflicts with the demand of the start time variable */
4092  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4093  peak = pos;
4094 
4095  pos++;
4096  }
4097  while( pos < ntimepoints && SCIPprofileGetTime(profile, pos) < ect );
4098 
4099  /* if we found no peak that means current the job could be scheduled at its earliest start time without
4100  * conflicting to the core resource profile
4101  */
4102  /* coverity[check_after_sink] */
4103  if( peak == -1 )
4104  break;
4105 
4106  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4107  * profile. That means we have to move it to the next time point in the resource profile but at most to the
4108  * earliest completion time (the remaining move will done in the next loop)
4109  */
4110  newlb = SCIPprofileGetTime(profile, peak+1);
4111  newlb = MIN(newlb, ect);
4112 
4113  /* if the earliest start time is greater than the lst we detected an infeasibilty */
4114  if( newlb > lst )
4115  {
4116  SCIPdebugMsg(scip, "variable <%s>: cannot be scheduled\n", SCIPvarGetName(var));
4117 
4118  /* use conflict analysis to analysis the core insertion which was infeasible */
4119  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
4120  var, duration, demand, newlb-1, usebdwidening, initialized, explanation) );
4121 
4122  if( explanation != NULL )
4123  explanation[idx] = TRUE;
4124 
4125  *infeasible = TRUE;
4126 
4127  break;
4128  }
4129 
4130  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4131  * bound change
4132  */
4133  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newlb-1);
4134 
4135  /* perform the bound lower bound change */
4136  if( inferInfoIsValid(inferinfo) )
4137  {
4138  SCIP_CALL( SCIPinferVarLbCons(scip, var, (SCIP_Real)newlb, cons, inferInfoToInt(inferinfo), TRUE, infeasible, &tightened) );
4139  }
4140  else
4141  {
4142  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)newlb, TRUE, infeasible, &tightened) );
4143  }
4144  assert(tightened);
4145  assert(!(*infeasible));
4146 
4147  SCIPdebugMsg(scip, "variable <%s> new lower bound <%d> -> <%d>\n", SCIPvarGetName(var), est, newlb);
4148  (*nchgbds)++;
4149 
4150  /* for the statistic we count the number of times a lower bound was tightened due the the time-table algorithm */
4152 
4153  /* adjust the earliest start time
4154  *
4155  * @note We are taking the lower of the start time variable on purpose instead of newlb. This is due the fact that
4156  * the proposed lower bound might be even strength by be the core which can be the case if aggregations are
4157  * involved.
4158  */
4159  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4160  assert(est >= newlb);
4161 
4162  /* adjust the search position for the resource profile for the next step */
4163  if( est == SCIPprofileGetTime(profile, peak+1) )
4164  pos = peak + 1;
4165  else
4166  pos = peak;
4167  }
4168  while( est < lst );
4169 
4170  return SCIP_OKAY;
4171 }
4172 
4173 /** We are using the core resource profile which contains all core except the one of the start time variable which we
4174  * want to propagate, to decrease the latest start time. This we are doing in steps of length at most the duration of
4175  * the job. The reason for that is, that this makes it later easier to resolve this propagation during the conflict
4176  * analysis
4177  */
4178 static
4180  SCIP* scip, /**< SCIP data structure */
4181  SCIP_VAR* var, /**< start time variable to propagate */
4182  int duration, /**< duration of the job */
4183  int demand, /**< demand of the job */
4184  int capacity, /**< cumulative capacity */
4185  SCIP_CONS* cons, /**< constraint which is propagated */
4186  SCIP_PROFILE* profile, /**< resource profile */
4187  int idx, /**< position of the variable to propagate */
4188  int* nchgbds /**< pointer to store the number of bound changes */
4189  )
4190 {
4191  int ntimepoints;
4192  int newub;
4193  int peak;
4194  int pos;
4195  int est;
4196  int lst;
4197  int lct;
4198 
4199  assert(var != NULL);
4200  assert(duration > 0);
4201  assert(demand > 0);
4202 
4203  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
4204  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4205 
4206  /* in case the start time variable is fixed do nothing */
4207  if( est == lst )
4208  return SCIP_OKAY;
4209 
4210  ntimepoints = SCIPprofileGetNTimepoints(profile);
4211 
4212  lct = lst + duration;
4213 
4214  /* first we find left position of latest completion time minus 1 (upper bound + duration) in resource profile; That
4215  * is the last time point where the job would run if schedule it at its latest start time (upper bound). This
4216  * position gives us the load which we have at the latest completion time minus one
4217  */
4218  (void) SCIPprofileFindLeft(profile, lct - 1, &pos);
4219 
4220  SCIPdebugMsg(scip, "propagate upper bound (pos %d)\n", pos);
4221  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
4222 
4223  if( pos == ntimepoints-1 && SCIPprofileGetTime(profile, pos) == lst )
4224  return SCIP_OKAY;
4225 
4226  /* we now trying to move the latest start time in steps of at most "duration" length */
4227  do
4228  {
4229  INFERINFO inferinfo;
4230  SCIP_Bool tightened;
4231  SCIP_Bool infeasible;
4232 
4233  peak = -1;
4234 
4235 #ifndef NDEBUG
4236  {
4237  /* in debug mode we check that we adjust the search position correctly */
4238  int tmppos;
4239 
4240  (void)SCIPprofileFindLeft(profile, lct - 1, &tmppos);
4241  assert(pos == tmppos);
4242  }
4243 #endif
4244 
4245  /* we search for a peak within the core profile which conflicts with the demand of the start time variable; we
4246  * want a peak which is closest to the latest start time
4247  */
4248  do
4249  {
4250  if( SCIPprofileGetLoad(profile, pos) + demand > capacity )
4251  peak = pos;
4252 
4253  pos--;
4254  }
4255  while( pos >= 0 && SCIPprofileGetTime(profile, pos+1) > lst);
4256 
4257  /* if we found no peak that means the current job could be scheduled at its latest start time without conflicting
4258  * to the core resource profile
4259  */
4260  /* coverity[check_after_sink] */
4261  if( peak == -1 )
4262  break;
4263 
4264  /* the peak position gives us a time point where the start time variable is in conflict with the resource
4265  * profile. That means the job has be done until that point. Hence that gives us the latest completion
4266  * time. Note that that we want to move the bound by at most the duration length (the remaining move we are
4267  * doing in the next loop)
4268  */
4269  newub = SCIPprofileGetTime(profile, peak);
4270  newub = MAX(newub, lst) - duration;
4271  assert(newub >= est);
4272 
4273  /* construct the inference information which we are using with the conflict analysis to resolve that particular
4274  * bound change
4275  */
4276  inferinfo = getInferInfo(PROPRULE_1_CORETIMES, idx, newub+duration);
4277 
4278  /* perform the bound upper bound change */
4279  if( inferInfoIsValid(inferinfo) )
4280  {
4281  SCIP_CALL( SCIPinferVarUbCons(scip, var, (SCIP_Real)newub, cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
4282  }
4283  else
4284  {
4285  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)newub, TRUE, &infeasible, &tightened) );
4286  }
4287  assert(tightened);
4288  assert(!infeasible);
4289 
4290  SCIPdebugMsg(scip, "variable <%s>: new upper bound <%d> -> <%d>\n", SCIPvarGetName(var), lst, newub);
4291  (*nchgbds)++;
4292 
4293  /* for the statistic we count the number of times a upper bound was tightened due the the time-table algorithm */
4295 
4296  /* adjust the latest start and completion time
4297  *
4298  * @note We are taking the upper of the start time variable on purpose instead of newub. This is due the fact that
4299  * the proposed upper bound might be even strength by be the core which can be the case if aggregations are
4300  * involved.
4301  */
4302  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
4303  assert(lst <= newub);
4304  lct = lst + duration;
4305 
4306  /* adjust the search position for the resource profile for the next step */
4307  if( SCIPprofileGetTime(profile, peak) == lct )
4308  pos = peak - 1;
4309  else
4310  pos = peak;
4311  }
4312  while( est < lst );
4313 
4314  return SCIP_OKAY;
4315 }
4316 
4317 /** compute for the different earliest start and latest completion time the core energy of the corresponding time
4318  * points
4319  */
4320 static
4322  SCIP_PROFILE* profile, /**< core profile */
4323  int nvars, /**< number of start time variables (activities) */
4324  int* ests, /**< array of sorted earliest start times */
4325  int* lcts, /**< array of sorted latest completion times */
4326  int* coreEnergyAfterEst, /**< array to store the core energy after the earliest start time of each job */
4327  int* coreEnergyAfterLct /**< array to store the core energy after the latest completion time of each job */
4328  )
4329 {
4330  int ntimepoints;
4331  int energy;
4332  int t;
4333  int v;
4334 
4335  ntimepoints = SCIPprofileGetNTimepoints(profile);
4336  t = ntimepoints - 1;
4337  energy = 0;
4338 
4339  /* compute core energy after the earliest start time of each job */
4340  for( v = nvars-1; v >= 0; --v )
4341  {
4342  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= ests[v] )
4343  {
4344  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4345  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4346  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4347  t--;
4348  }
4349  assert(SCIPprofileGetTime(profile, t) >= ests[v] || t == ntimepoints-1);
4350 
4351  /* maybe ests[j] is in-between two timepoints */
4352  if( SCIPprofileGetTime(profile, t) - ests[v] > 0 )
4353  {
4354  assert(t > 0);
4355  coreEnergyAfterEst[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - ests[v]);
4356  }
4357  else
4358  coreEnergyAfterEst[v] = energy;
4359  }
4360 
4361  t = ntimepoints - 1;
4362  energy = 0;
4363 
4364  /* compute core energy after the latest completion time of each job */
4365  for( v = nvars-1; v >= 0; --v )
4366  {
4367  while( t > 0 && SCIPprofileGetTime(profile, t-1) >= lcts[v] )
4368  {
4369  assert(SCIPprofileGetLoad(profile, t-1) >= 0);
4370  assert(SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1)>= 0);
4371  energy += SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - SCIPprofileGetTime(profile, t-1));
4372  t--;
4373  }
4374  assert(SCIPprofileGetTime(profile, t) >= lcts[v] || t == ntimepoints-1);
4375 
4376  /* maybe lcts[j] is in-between two timepoints */
4377  if( SCIPprofileGetTime(profile, t) - lcts[v] > 0 )
4378  {
4379  assert(t > 0);
4380  coreEnergyAfterLct[v] = energy + SCIPprofileGetLoad(profile, t-1) * (SCIPprofileGetTime(profile, t) - lcts[v]);
4381  }
4382  else
4383  coreEnergyAfterLct[v] = energy;
4384  }
4385 }
4386 
4387 /** collect earliest start times, latest completion time, and free energy contributions */
4388 static
4389 void collectDataTTEF(
4390  SCIP* scip, /**< SCIP data structure */
4391  int nvars, /**< number of start time variables (activities) */
4392  SCIP_VAR** vars, /**< array of start time variables */
4393  int* durations, /**< array of durations */
4394  int* demands, /**< array of demands */
4395  int hmin, /**< left bound of time axis to be considered (including hmin) */
4396  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4397  int* permests, /**< array to store the variable positions */
4398  int* ests, /**< array to store earliest start times */
4399  int* permlcts, /**< array to store the variable positions */
4400  int* lcts, /**< array to store latest completion times */
4401  int* ects, /**< array to store earliest completion times of the flexible part of the job */
4402  int* lsts, /**< array to store latest start times of the flexible part of the job */
4403  int* flexenergies /**< array to store the flexible energies of each job */
4404  )
4405 {
4406  int v;
4407 
4408  for( v = 0; v < nvars; ++ v)
4409  {
4410  int duration;
4411  int leftadjust;
4412  int rightadjust;
4413  int core;
4414  int est;
4415  int lct;
4416  int ect;
4417  int lst;
4418 
4419  duration = durations[v];
4420  assert(duration > 0);
4421 
4422  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4423  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
4424  ect = est + duration;
4425  lct = lst + duration;
4426 
4427  ests[v] = est;
4428  lcts[v] = lct;
4429  permests[v] = v;
4430  permlcts[v] = v;
4431 
4432  /* compute core time window which lies within the effective horizon */
4433  core = (int) computeCoreWithInterval(hmin, hmax, ect, lst);
4434 
4435  /* compute the number of time steps the job could run before the effective horizon */
4436  leftadjust = MAX(0, hmin - est);
4437 
4438  /* compute the number of time steps the job could run after the effective horizon */
4439  rightadjust = MAX(0, lct - hmax);
4440 
4441  /* compute for each job the energy which is flexible; meaning not part of the core */
4442  flexenergies[v] = duration - leftadjust - rightadjust - core;
4443  flexenergies[v] = MAX(0, flexenergies[v]);
4444  flexenergies[v] *= demands[v];
4445  assert(flexenergies[v] >= 0);
4446 
4447  /* the earliest completion time of the flexible energy */
4448  ects[v] = MIN(ect, lst);
4449 
4450  /* the latest start time of the flexible energy */
4451  lsts[v] = MAX(ect, lst);
4452  }
4453 }
4454 
4455 /** try to tighten the lower bound of the given variable */
4456 static
4458  SCIP* scip, /**< SCIP data structure */
4459  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4460  int nvars, /**< number of start time variables (activities) */
4461  SCIP_VAR** vars, /**< array of start time variables */
4462  int* durations, /**< array of durations */
4463  int* demands, /**< array of demands */
4464  int capacity, /**< cumulative capacity */
4465  int hmin, /**< left bound of time axis to be considered (including hmin) */
4466  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4467  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4468  int duration, /**< duration of the job */
4469  int demand, /**< demand of the job */
4470  int est, /**< earliest start time of the job */
4471  int ect, /**< earliest completion time of the flexible part of the job */
4472  int lct, /**< latest completion time of the job */
4473  int begin, /**< begin of the time window under investigation */
4474  int end, /**< end of the time window under investigation */
4475  SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4476  int* bestlb, /**< pointer to strope the best lower bound change */
4477  int* inferinfos, /**< pointer to store the inference information which is need for the (best) lower bound change */
4478  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4479  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4480  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4481  )
4482 {
4483  int newlb;
4484 
4485  assert(begin >= hmin);
4486  assert(end <= hmax);
4487 
4488  /* check if the time-table edge-finding should infer bounds */
4489  if( !conshdlrdata->ttefinfer )
4490  return SCIP_OKAY;
4491 
4492  /* if the job can be processed completely before or after the time window, nothing can be tightened */
4493  if( est >= end || ect <= begin )
4494  return SCIP_OKAY;
4495 
4496  /* if flexible part runs completely within the time window (assuming it is scheduled on its earliest start time), we
4497  * skip since the overload check will do the job
4498  */
4499  if( est >= begin && ect <= end )
4500  return SCIP_OKAY;
4501 
4502  /* check if the available energy in the time window is to small to handle the flexible part if it is schedule on its
4503  * earliest start time
4504  */
4505  if( energy >= demand * ((SCIP_Longint) MAX(begin, est) - MIN(end, ect)) )
4506  return SCIP_OKAY;
4507 
4508  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4509  * present; therefore, we need to add the core;
4510  *
4511  * @note the variable ect define the earliest completion time of the flexible part of the job; hence we need to
4512  * compute the earliest completion time of the (whole) job
4513  */
4514  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4515 
4516  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4517  *
4518  * @note we can round down the compute duration w.r.t. the available energy
4519  */
4520  newlb = end - (int) (energy / demand);
4521 
4522  /* check if we detected an infeasibility which is the case if the new lower bound is larger than the current upper
4523  * bound (latest start time); meaning it is not possible to schedule the job
4524  */
4525  if( newlb > lct - duration )
4526  {
4527  /* initialize conflict analysis if conflict analysis is applicable */
4529  {
4530  SCIP_Real relaxedbd;
4531 
4532  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) < newlb);
4533 
4534  /* it is enough to overshoot the upper bound of the variable by one */
4535  relaxedbd = SCIPvarGetUbLocal(var) + 1.0;
4536 
4537  /* initialize conflict analysis */
4539 
4540  /* added to upper bound (which was overcut be new lower bound) of the variable */
4541  SCIP_CALL( SCIPaddConflictUb(scip, var, NULL) );
4542 
4543  /* analyze the infeasible */
4544  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4545  begin, end, var, SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4546 
4547  (*initialized) = TRUE;
4548  }
4549 
4550  (*cutoff) = TRUE;
4551  }
4552  else if( newlb > (*bestlb) )
4553  {
4554  INFERINFO inferinfo;
4555 
4556  assert(newlb > begin);
4557 
4558  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4559 
4560  /* construct inference information */
4561  (*inferinfos) = inferInfoToInt(inferinfo);
4562  (*bestlb) = newlb;
4563  }
4564 
4565  return SCIP_OKAY;
4566 }
4567 
4568 /** try to tighten the upper bound of the given variable */
4569 static
4571  SCIP* scip, /**< SCIP data structure */
4572  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4573  int nvars, /**< number of start time variables (activities) */
4574  SCIP_VAR** vars, /**< array of start time variables */
4575  int* durations, /**< array of durations */
4576  int* demands, /**< array of demands */
4577  int capacity, /**< cumulative capacity */
4578  int hmin, /**< left bound of time axis to be considered (including hmin) */
4579  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4580  SCIP_VAR* var, /**< variable to be considered for upper bound tightening */
4581  int duration, /**< duration of the job */
4582  int demand, /**< demand of the job */
4583  int est, /**< earliest start time of the job */
4584  int lst, /**< latest start time of the flexible part of the job */
4585  int lct, /**< latest completion time of the job */
4586  int begin, /**< begin of the time window under investigation */
4587  int end, /**< end of the time window under investigation */
4588  SCIP_Longint energy, /**< available energy for the flexible part of the hob within the time window */
4589  int* bestub, /**< pointer to strope the best upper bound change */
4590  int* inferinfos, /**< pointer to store the inference information which is need for the (best) upper bound change */
4591  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4592  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4593  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4594  )
4595 {
4596  int newub;
4597 
4598  assert(begin >= hmin);
4599  assert(end <= hmax);
4600  assert(est < begin);
4601 
4602  /* check if the time-table edge-finding should infer bounds */
4603  if( !conshdlrdata->ttefinfer )
4604  return SCIP_OKAY;
4605 
4606  /* if flexible part of the job can be processed completely before or after the time window, nothing can be tightened */
4607  if( lst >= end || lct <= begin )
4608  return SCIP_OKAY;
4609 
4610  /* if flexible part runs completely within the time window (assuming it is scheduled on its latest start time), we
4611  * skip since the overload check will do the job
4612  */
4613  if( lst >= begin && lct <= end )
4614  return SCIP_OKAY;
4615 
4616  /* check if the available energy in the time window is to small to handle the flexible part of the job */
4617  if( energy >= demand * ((SCIP_Longint) MIN(end, lct) - MAX(begin, lst)) )
4618  return SCIP_OKAY;
4619 
4620  /* adjust the available energy for the job; the given available energy assumes that the core of the considered job is
4621  * present; therefore, we need to add the core;
4622  *
4623  * @note the variable lst define the latest start time of the flexible part of the job; hence we need to compute the
4624  * latest start of the (whole) job
4625  */
4626  energy += computeCoreWithInterval(begin, end, est + duration, lct - duration) * demand;
4627  assert(energy >= 0);
4628 
4629  /* compute a latest start time (upper bound) such that the job consums at most the available energy
4630  *
4631  * @note we can round down the compute duration w.r.t. the available energy
4632  */
4633  assert(demand > 0);
4634  newub = begin - duration + (int) (energy / demand);
4635 
4636  /* check if we detected an infeasibility which is the case if the new upper bound is smaller than the current lower
4637  * bound (earliest start time); meaning it is not possible to schedule the job
4638  */
4639  if( newub < est )
4640  {
4641  /* initialize conflict analysis if conflict analysis is applicable */
4643  {
4644  SCIP_Real relaxedbd;
4645 
4646  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) > newub);
4647 
4648  /* it is enough to undershoot the lower bound of the variable by one */
4649  relaxedbd = SCIPvarGetLbLocal(var) - 1.0;
4650 
4651  /* initialize conflict analysis */
4653 
4654  /* added to lower bound (which was undercut be new upper bound) of the variable */
4655  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
4656 
4657  /* analyze the infeasible */
4658  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4659  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd, conshdlrdata->usebdwidening, explanation) );
4660 
4661  (*initialized) = TRUE;
4662  }
4663 
4664  (*cutoff) = TRUE;
4665  }
4666  else if( newub < (*bestub) )
4667  {
4668  INFERINFO inferinfo;
4669 
4670  assert(newub < begin);
4671 
4672  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
4673 
4674  /* construct inference information */
4675  (*inferinfos) = inferInfoToInt(inferinfo);
4676  (*bestub) = newub;
4677  }
4678 
4679  return SCIP_OKAY;
4680 }
4681 
4682 /** propagate the upper bounds and "opportunistically" the lower bounds using the time-table edge-finding algorithm */
4683 static
4685  SCIP* scip, /**< SCIP data structure */
4686  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4687  int nvars, /**< number of start time variables (activities) */
4688  SCIP_VAR** vars, /**< array of start time variables */
4689  int* durations, /**< array of durations */
4690  int* demands, /**< array of demands */
4691  int capacity, /**< cumulative capacity */
4692  int hmin, /**< left bound of time axis to be considered (including hmin) */
4693  int hmax, /**< right bound of time axis to be considered (not including hmax) */
4694  int* newlbs, /**< array to buffer new lower bounds */
4695  int* newubs, /**< array to buffer new upper bounds */
4696  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
4697  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
4698  int* lsts, /**< array of latest start time of the flexible part in the same order as the variables */
4699  int* flexenergies, /**< array of flexible energies in the same order as the variables */
4700  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the earliest start times */
4701  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
4702  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
4703  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
4704  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
4705  SCIP_Bool* initialized, /**< was conflict analysis initialized */
4706  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
4707  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
4708  )
4709 {
4710  int coreEnergyAfterEnd;
4711  SCIP_Longint maxavailable;
4712  SCIP_Longint minavailable;
4713  SCIP_Longint totalenergy;
4714  int nests;
4715  int est;
4716  int lct;
4717  int start;
4718  int end;
4719  int v;
4720 
4721  est = INT_MAX;
4722  lct = INT_MIN;
4723 
4724  /* compute earliest start and latest completion time of all jobs */
4725  for( v = 0; v < nvars; ++v )
4726  {
4727  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
4728  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
4729 
4730  est = MIN(est, start);
4731  lct = MAX(lct, end);
4732  }
4733 
4734  /* adjust the effective time horizon */
4735  hmin = MAX(hmin, est);
4736  hmax = MIN(hmax, lct);
4737 
4738  end = hmax + 1;
4739  coreEnergyAfterEnd = -1;
4740 
4741  maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
4742  minavailable = maxavailable;
4743  totalenergy = computeTotalEnergy(durations, demands, nvars);
4744 
4745  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
4746  if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
4747  return SCIP_OKAY;
4748 
4749  nests = nvars;
4750 
4751  /* loop over all variable in non-increasing order w.r.t. the latest completion time; thereby, the latest completion
4752  * times define the end of the time interval under investigation
4753  */
4754  for( v = nvars-1; v >= 0 && !(*cutoff); --v )
4755  {
4756  int flexenergy;
4757  int minbegin;
4758  int lbenergy;
4759  int lbcand;
4760  int i;
4761 
4762  lct = lcts[v];
4763 
4764  /* if the latest completion time is larger then hmax an infeasibility cannot be detected, since after hmax an
4765  * infinity capacity is available; hence we skip that
4766  */
4767  if( lct > hmax )
4768  continue;
4769 
4770  /* if the latest completion time is smaller then hmin we have to stop */
4771  if( lct <= hmin )
4772  {
4773  assert(v == 0 || lcts[v-1] <= lcts[v]);
4774  break;
4775  }
4776 
4777  /* if the latest completion time equals to previous end time, we can continue since this particular interval
4778  * induced by end was just analyzed
4779  */
4780  if( lct == end )
4781  continue;
4782 
4783  assert(lct < end);
4784 
4785  /* In case we only want to detect an overload (meaning no bound propagation) we can skip the interval; this is
4786  * the case if the free energy (the energy which is not occupied by any core) is smaller than the previous minimum
4787  * free energy; if so it means that in the next iterate the free-energy cannot be negative
4788  */
4789  if( !conshdlrdata->ttefinfer && end <= hmax && minavailable < maxavailable )
4790  {
4791  SCIP_Longint freeenergy;
4792 
4793  assert(coreEnergyAfterLct[v] >= coreEnergyAfterEnd);
4794  assert(coreEnergyAfterEnd >= 0);
4795 
4796  /* compute the energy which is not consumed by the cores with in the interval [lct, end) */
4797  freeenergy = capacity * ((SCIP_Longint) end - lct) - coreEnergyAfterLct[v] + coreEnergyAfterEnd;
4798 
4799  if( freeenergy <= minavailable )
4800  {
4801  SCIPdebugMsg(scip, "skip latest completion time <%d> (minimum available energy <%" SCIP_LONGINT_FORMAT ">, free energy <%" SCIP_LONGINT_FORMAT ">)\n", lct, minavailable, freeenergy);
4802  continue;
4803  }
4804  }
4805 
4806  SCIPdebugMsg(scip, "check intervals ending with <%d>\n", lct);
4807 
4808  end = lct;
4809  coreEnergyAfterEnd = coreEnergyAfterLct[v];
4810 
4811  flexenergy = 0;
4812  minavailable = maxavailable;
4813  minbegin = hmax;
4814  lbcand = -1;
4815  lbenergy = 0;
4816 
4817  /* loop over the job in non-increasing order w.r.t. the earliest start time; these earliest start time are
4818  * defining the beginning of the time interval under investigation; Thereby, the time interval gets wider and
4819  * wider
4820  */
4821  for( i = nests-1; i >= 0; --i )
4822  {
4823  SCIP_VAR* var;
4824  SCIP_Longint freeenergy;
4825  int duration;
4826  int demand;
4827  int begin;
4828  int idx;
4829  int lst;
4830 
4831  idx = perm[i];
4832  assert(idx >= 0);
4833  assert(idx < nvars);
4834  assert(!(*cutoff));
4835 
4836  /* the earliest start time of the job */
4837  est = ests[i];
4838 
4839  /* if the job starts after the current end, we can skip it and do not need to consider it again since the
4840  * latest completion times (which define end) are scant in non-increasing order
4841  */
4842  if( end <= est )
4843  {
4844  nests--;
4845  continue;
4846  }
4847 
4848  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals with the
4849  * current ending time
4850  */
4851  if( ((SCIP_Longint) end - est) * capacity >= totalenergy )
4852  break;
4853 
4854  var = vars[idx];
4855  assert(var != NULL);
4856 
4857  duration = durations[idx];
4858  assert(duration > 0);
4859 
4860  demand = demands[idx];
4861  assert(demand > 0);
4862 
4863  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
4864 
4865  /* the latest start time of the free part of the job */
4866  lst = lsts[idx];
4867 
4868  /* in case the earliest start time is equal to minbegin, the job lies completely within the time window under
4869  * investigation; hence the overload check will do the the job
4870  */
4871  assert(est <= minbegin);
4872  if( minavailable < maxavailable && est < minbegin )
4873  {
4874  assert(!(*cutoff));
4875 
4876  /* try to tighten the upper bound */
4877  SCIP_CALL( tightenUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
4878  var, duration, demand, est, lst, lct, minbegin, end, minavailable, &(newubs[idx]), &(ubinferinfos[idx]),
4879  initialized, explanation, cutoff) );
4880 
4881  if( *cutoff )
4882  break;
4883  }
4884 
4885  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, lst of free part <%d>\n",
4886  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, lst);
4887 
4888  begin = est;
4889  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) == est);
4890 
4891  /* if the earliest start time is smaller than hmin we can stop here since the next job will not decrease the
4892  * free energy
4893  */
4894  if( begin < hmin )
4895  break;
4896 
4897  /* compute the contribution to the flexible energy */
4898  if( lct <= end )
4899  {
4900  /* if the jobs has to finish before the end, all the energy has to be scheduled */
4901  assert(lst >= begin);
4902  assert(flexenergies[idx] >= 0);
4903  flexenergy += flexenergies[idx];
4904  }
4905  else
4906  {
4907  /* the job partly overlaps with the end */
4908  int candenergy;
4909  int energy;
4910 
4911  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
4912  * w.r.t. latest start time
4913  *
4914  * @note we need to be aware of the effective horizon
4915  */
4916  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (end - lst)));
4917  assert(end - lst < duration);
4918  assert(energy >= 0);
4919 
4920  /* adjust the flexible energy of the time interval */
4921  flexenergy += energy;
4922 
4923  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
4924  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
4925  assert(candenergy >= 0);
4926 
4927  /* check if we found a better candidate */
4928  if( candenergy > lbenergy )
4929  {
4930  lbenergy = candenergy;
4931  lbcand = idx;
4932  }
4933  }
4934 
4935  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
4936  assert(coreEnergyAfterEst[i] >= coreEnergyAfterEnd);
4937 
4938  /* compute the energy which is not used yet */
4939  freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterEst[i] + coreEnergyAfterEnd;
4940 
4941  /* check overload */
4942  if( freeenergy < 0 )
4943  {
4944  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
4945 
4946  /* initialize conflict analysis if conflict analysis is applicable */
4948  {
4949  /* analyze infeasibilty */
4951 
4952  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4953  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
4954  conshdlrdata->usebdwidening, explanation) );
4955 
4956  (*initialized) = TRUE;
4957  }
4958 
4959  (*cutoff) = TRUE;
4960 
4961  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
4962  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
4963 
4964  break;
4965  }
4966 
4967  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
4968  if( lbenergy > 0 && freeenergy < lbenergy )
4969  {
4970  SCIP_Longint energy;
4971  int newlb;
4972  int ect;
4973 
4974  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[lbcand])) + durations[lbcand];
4975  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[lbcand]));
4976 
4977  /* remove the energy of our job from the ... */
4978  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) end - lsts[lbcand])) * demands[lbcand];
4979 
4980  newlb = end - (int)(energy / demands[lbcand]);
4981 
4982  if( newlb > lst )
4983  {
4984  /* initialize conflict analysis if conflict analysis is applicable */
4986  {
4987  SCIP_Real relaxedbd;
4988 
4989  /* analyze infeasibilty */
4991 
4992  relaxedbd = lst + 1.0;
4993 
4994  /* added to upper bound (which was overcut be new lower bound) of the variable */
4995  SCIP_CALL( SCIPaddConflictUb(scip, vars[lbcand], NULL) );
4996 
4997  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
4998  begin, end, vars[lbcand], SCIP_BOUNDTYPE_LOWER, NULL, relaxedbd,
4999  conshdlrdata->usebdwidening, explanation) );
5000 
5001  (*initialized) = TRUE;
5002  }
5003 
5004  (*cutoff) = TRUE;
5005  break;
5006  }
5007  else if( newlb > newlbs[lbcand] )
5008  {
5009  INFERINFO inferinfo;
5010 
5011  /* construct inference information */
5012  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5013 
5014  /* buffer upper bound change */
5015  lbinferinfos[lbcand] = inferInfoToInt(inferinfo);
5016  newlbs[lbcand] = newlb;
5017  }
5018  }
5019 
5020  /* check if the current interval has a smaller free energy */
5021  if( minavailable > freeenergy )
5022  {
5023  minavailable = freeenergy;
5024  minbegin = begin;
5025  }
5026  assert(minavailable >= 0);
5027  }
5028  }
5029 
5030  return SCIP_OKAY;
5031 }
5032 
5033 /** propagate the lower bounds and "opportunistically" the upper bounds using the time-table edge-finding algorithm */
5034 static
5036  SCIP* scip, /**< SCIP data structure */
5037  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5038  int nvars, /**< number of start time variables (activities) */
5039  SCIP_VAR** vars, /**< array of start time variables */
5040  int* durations, /**< array of durations */
5041  int* demands, /**< array of demands */
5042  int capacity, /**< cumulative capacity */
5043  int hmin, /**< left bound of time axis to be considered (including hmin) */
5044  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5045  int* newlbs, /**< array to buffer new lower bounds */
5046  int* newubs, /**< array to buffer new upper bounds */
5047  int* lbinferinfos, /**< array to store the inference information for the lower bound changes */
5048  int* ubinferinfos, /**< array to store the inference information for the upper bound changes */
5049  int* ects, /**< array of earliest completion time of the flexible part in the same order as the variables */
5050  int* flexenergies, /**< array of flexible energies in the same order as the variables */
5051  int* perm, /**< permutation of the variables w.r.t. the non-decreasing order of the latest completion times */
5052  int* ests, /**< array with earliest strart times sorted in non-decreasing order */
5053  int* lcts, /**< array with latest completion times sorted in non-decreasing order */
5054  int* coreEnergyAfterEst, /**< core energy after the earliest start times */
5055  int* coreEnergyAfterLct, /**< core energy after the latest completion times */
5056  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5057  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5058  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5059  )
5060 {
5061  int coreEnergyAfterStart;
5062  SCIP_Longint maxavailable;
5063  SCIP_Longint minavailable;
5064  SCIP_Longint totalenergy;
5065  int nlcts;
5066  int begin;
5067  int minest;
5068  int maxlct;
5069  int start;
5070  int end;
5071  int v;
5072 
5073  if( *cutoff )
5074  return SCIP_OKAY;
5075 
5076  begin = hmin - 1;
5077 
5078  minest = INT_MAX;
5079  maxlct = INT_MIN;
5080 
5081  /* compute earliest start and latest completion time of all jobs */
5082  for( v = 0; v < nvars; ++v )
5083  {
5084  start = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5085  end = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v])) + durations[v];
5086 
5087  minest = MIN(minest, start);
5088  maxlct = MAX(maxlct, end);
5089  }
5090 
5091  /* adjust the effective time horizon */
5092  hmin = MAX(hmin, minest);
5093  hmax = MIN(hmax, maxlct);
5094 
5095  maxavailable = ((SCIP_Longint) hmax - hmin) * capacity;
5096  totalenergy = computeTotalEnergy(durations, demands, nvars);
5097 
5098  /* check if the smallest interval has a size such that the total energy fits, if so we can skip the propagator */
5099  if( ((SCIP_Longint) lcts[0] - ests[nvars-1]) * capacity >= totalenergy )
5100  return SCIP_OKAY;
5101 
5102  nlcts = 0;
5103 
5104  /* loop over all variable in non-decreasing order w.r.t. the earliest start times; thereby, the earliest start times
5105  * define the start of the time interval under investigation
5106  */
5107  for( v = 0; v < nvars; ++v )
5108  {
5109  int flexenergy;
5110  int minend;
5111  int ubenergy;
5112  int ubcand;
5113  int est;
5114  int i;
5115 
5116  est = ests[v];
5117 
5118  /* if the earliest start time is smaller then hmin an infeasibility cannot be detected, since before hmin an
5119  * infinity capacity is available; hence we skip that
5120  */
5121  if( est < hmin )
5122  continue;
5123 
5124  /* if the earliest start time is larger or equal then hmax we have to stop */
5125  if( est >= hmax )
5126  break;
5127 
5128  /* if the latest earliest start time equals to previous start time, we can continue since this particular interval
5129  * induced by start was just analyzed
5130  */
5131  if( est == begin )
5132  continue;
5133 
5134  assert(est > begin);
5135 
5136  SCIPdebugMsg(scip, "check intervals starting with <%d>\n", est);
5137 
5138  begin = est;
5139  coreEnergyAfterStart = coreEnergyAfterEst[v];
5140 
5141  flexenergy = 0;
5142  minavailable = maxavailable;
5143  minend = hmin;
5144  ubcand = -1;
5145  ubenergy = 0;
5146 
5147  /* loop over the job in non-decreasing order w.r.t. the latest completion time; these latest completion times are
5148  * defining the ending of the time interval under investigation; thereby, the time interval gets wider and wider
5149  */
5150  for( i = nlcts; i < nvars; ++i )
5151  {
5152  SCIP_VAR* var;
5153  SCIP_Longint freeenergy;
5154  int duration;
5155  int demand;
5156  int idx;
5157  int lct;
5158  int ect;
5159 
5160  idx = perm[i];
5161  assert(idx >= 0);
5162  assert(idx < nvars);
5163  assert(!(*cutoff));
5164 
5165  /* the earliest start time of the job */
5166  lct = lcts[i];
5167 
5168  /* if the job has a latest completion time before the the current start, we can skip it and do not need to
5169  * consider it again since the earliest start times (which define the start) are scant in non-decreasing order
5170  */
5171  if( lct <= begin )
5172  {
5173  nlcts++;
5174  continue;
5175  }
5176 
5177  /* check if the interval has a size such that the total energy fits, if so we can skip all intervals which
5178  * start with current beginning time
5179  */
5180  if( ((SCIP_Longint) lct - begin) * capacity >= totalenergy )
5181  break;
5182 
5183  var = vars[idx];
5184  assert(var != NULL);
5185 
5186  duration = durations[idx];
5187  assert(duration > 0);
5188 
5189  demand = demands[idx];
5190  assert(demand > 0);
5191 
5192  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5193 
5194  /* the earliest completion time of the flexible part of the job */
5195  ect = ects[idx];
5196 
5197  /* in case the latest completion time is equal to minend, the job lies completely within the time window under
5198  * investigation; hence the overload check will do the the job
5199  */
5200  assert(lct >= minend);
5201  if( minavailable < maxavailable && lct > minend )
5202  {
5203  assert(!(*cutoff));
5204 
5205  /* try to tighten the upper bound */
5206  SCIP_CALL( tightenLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5207  var, duration, demand, est, ect, lct, begin, minend, minavailable, &(newlbs[idx]), &(lbinferinfos[idx]),
5208  initialized, explanation, cutoff) );
5209 
5210  if( *cutoff )
5211  return SCIP_OKAY;
5212  }
5213 
5214  SCIPdebugMsg(scip, "check variable <%s>[%g,%g] (duration %d, demands %d, est <%d>, ect of free part <%d>\n",
5215  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, est, ect);
5216 
5217  end = lct;
5218  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration == lct);
5219 
5220  /* if the latest completion time is larger than hmax we can stop here since the next job will not decrease the
5221  * free energy
5222  */
5223  if( end > hmax )
5224  break;
5225 
5226  /* compute the contribution to the flexible energy */
5227  if( est >= begin )
5228  {
5229  /* if the jobs has to finish before the end, all the energy has to be scheduled */
5230  assert(ect <= end);
5231  assert(flexenergies[idx] >= 0);
5232  flexenergy += flexenergies[idx];
5233  }
5234  else
5235  {
5236  /* the job partly overlaps with the end */
5237  int candenergy;
5238  int energy;
5239 
5240  /* compute the flexible energy which is part of the time interval for sure if the job is scheduled
5241  * w.r.t. latest start time
5242  *
5243  * @note we need to be aware of the effective horizon
5244  */
5245  energy = MIN(flexenergies[idx], demands[idx] * MAX(0, (ect - begin)));
5246  assert(ect - begin < duration);
5247  assert(energy >= 0);
5248 
5249  /* adjust the flexible energy of the time interval */
5250  flexenergy += energy;
5251 
5252  /* compute the flexible energy of the job which is not part of flexible energy of the time interval */
5253  candenergy = MIN(flexenergies[idx], demands[idx] * (end - begin)) - energy;
5254  assert(candenergy >= 0);
5255 
5256  /* check if we found a better candidate */
5257  if( candenergy > ubenergy )
5258  {
5259  ubenergy = candenergy;
5260  ubcand = idx;
5261  }
5262  }
5263 
5264  SCIPdebugMsg(scip, "time window [%d,%d) flexible energy <%d>\n", begin, end, flexenergy);
5265  assert(coreEnergyAfterLct[i] <= coreEnergyAfterStart);
5266 
5267  /* compute the energy which is not used yet */
5268  freeenergy = capacity * ((SCIP_Longint) end - begin) - flexenergy - coreEnergyAfterStart + coreEnergyAfterLct[i];
5269 
5270  /* check overload */
5271  if( freeenergy < 0 )
5272  {
5273  SCIPdebugMsg(scip, "analyze overload within time window [%d,%d) capacity %d\n", begin, end, capacity);
5274 
5275  /* initialize conflict analysis if conflict analysis is applicable */
5277  {
5278  /* analyze infeasibilty */
5280 
5281  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5282  begin, end, NULL, SCIP_BOUNDTYPE_UPPER, NULL, SCIP_UNKNOWN,
5283  conshdlrdata->usebdwidening, explanation) );
5284 
5285  (*initialized) = TRUE;
5286  }
5287 
5288  (*cutoff) = TRUE;
5289 
5290  /* for the statistic we count the number of times a cutoff was detected due the time-time-edge-finding */
5291  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5292 
5293  return SCIP_OKAY;
5294  }
5295 
5296  /* check if the available energy is not sufficent to schedule the flexible energy of the best candidate job */
5297  if( ubenergy > 0 && freeenergy < ubenergy )
5298  {
5299  SCIP_Longint energy;
5300  int newub;
5301  int lst;
5302 
5303  duration = durations[ubcand];
5304  assert(duration > 0);
5305 
5306  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[ubcand])) + duration;
5307  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[ubcand]));
5308 
5309  /* remove the energy of our job from the ... */
5310  energy = freeenergy + (computeCoreWithInterval(begin, end, ect, lst) + MAX(0, (SCIP_Longint) ects[ubcand] - begin)) * demands[ubcand];
5311 
5312  newub = begin - duration + (int)(energy / demands[ubcand]);
5313 
5314  if( newub < ect - duration )
5315  {
5316  /* initialize conflict analysis if conflict analysis is applicable */
5318  {
5319  SCIP_Real relaxedbd;
5320  /* analyze infeasibilty */
5322 
5323  relaxedbd = ect - duration - 1.0;
5324 
5325  /* added to lower bound (which was undercut be new upper bound) of the variable */
5326  SCIP_CALL( SCIPaddConflictUb(scip, vars[ubcand], NULL) );
5327 
5328  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5329  begin, end, vars[ubcand], SCIP_BOUNDTYPE_UPPER, NULL, relaxedbd,
5330  conshdlrdata->usebdwidening, explanation) );
5331 
5332  (*initialized) = TRUE;
5333  }
5334 
5335  (*cutoff) = TRUE;
5336  return SCIP_OKAY;
5337  }
5338  else if( newub < newubs[ubcand] )
5339  {
5340  INFERINFO inferinfo;
5341 
5342  /* construct inference information */
5343  inferinfo = getInferInfo(PROPRULE_3_TTEF, begin, end);
5344 
5345  /* buffer upper bound change */
5346  ubinferinfos[ubcand] = inferInfoToInt(inferinfo);
5347  newubs[ubcand] = newub;
5348  }
5349  }
5350 
5351  /* check if the current interval has a smaller free energy */
5352  if( minavailable > freeenergy )
5353  {
5354  minavailable = freeenergy;
5355  minend = end;
5356  }
5357  assert(minavailable >= 0);
5358  }
5359  }
5360 
5361  return SCIP_OKAY;
5362 }
5363 
5364 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of time-table
5365  * edge-finding
5366  *
5367  * @note The algorithm is based on the following two papers:
5368  * - Petr Vilim, "Timetable Edge Finding Filtering Algorithm for Discrete Cumulative Resources", In: Tobias
5369  * Achterberg and J. Christopher Beck (Eds.), Integration of AI and OR Techniques in Constraint Programming for
5370  * Combinatorial Optimization Problems (CPAIOR 2011), LNCS 6697, pp 230--245
5371  * - Andreas Schutt, Thibaut Feydy, and Peter J. Stuckey, "Explaining Time-Table-Edge-Finding Propagation for the
5372  * Cumulative Resource Constraint (submitted to CPAIOR 2013)
5373  */
5374 static
5376  SCIP* scip, /**< SCIP data structure */
5377  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5378  SCIP_PROFILE* profile, /**< current core profile */
5379  int nvars, /**< number of start time variables (activities) */
5380  SCIP_VAR** vars, /**< array of start time variables */
5381  int* durations, /**< array of durations */
5382  int* demands, /**< array of demands */
5383  int capacity, /**< cumulative capacity */
5384  int hmin, /**< left bound of time axis to be considered (including hmin) */
5385  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5386  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5387  int* nchgbds, /**< pointer to store the number of bound changes */
5388  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5389  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5390  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5391  )
5392 {
5393  int* coreEnergyAfterEst;
5394  int* coreEnergyAfterLct;
5395  int* flexenergies;
5396  int* permests;
5397  int* permlcts;
5398  int* lcts;
5399  int* ests;
5400  int* ects;
5401  int* lsts;
5402 
5403  int* newlbs;
5404  int* newubs;
5405  int* lbinferinfos;
5406  int* ubinferinfos;
5407 
5408  int v;
5409 
5410  /* check if a cutoff was already detected */
5411  if( (*cutoff) )
5412  return SCIP_OKAY;
5413 
5414  /* check if at least the basic overload checking should be perfomed */
5415  if( !conshdlrdata->ttefcheck )
5416  return SCIP_OKAY;
5417 
5418  SCIPdebugMsg(scip, "run time-table edge-finding overload checking\n");
5419 
5420  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterEst, nvars) );
5421  SCIP_CALL( SCIPallocBufferArray(scip, &coreEnergyAfterLct, nvars) );
5422  SCIP_CALL( SCIPallocBufferArray(scip, &flexenergies, nvars) );
5423  SCIP_CALL( SCIPallocBufferArray(scip, &permlcts, nvars) );
5424  SCIP_CALL( SCIPallocBufferArray(scip, &permests, nvars) );
5425  SCIP_CALL( SCIPallocBufferArray(scip, &lcts, nvars) );
5426  SCIP_CALL( SCIPallocBufferArray(scip, &ests, nvars) );
5427  SCIP_CALL( SCIPallocBufferArray(scip, &ects, nvars) );
5428  SCIP_CALL( SCIPallocBufferArray(scip, &lsts, nvars) );
5429 
5430  SCIP_CALL( SCIPallocBufferArray(scip, &newlbs, nvars) );
5431  SCIP_CALL( SCIPallocBufferArray(scip, &newubs, nvars) );
5432  SCIP_CALL( SCIPallocBufferArray(scip, &lbinferinfos, nvars) );
5433  SCIP_CALL( SCIPallocBufferArray(scip, &ubinferinfos, nvars) );
5434 
5435  /* we need to buffer the bound changes since the propagation algorithm cannot handle new bound dynamically */
5436  for( v = 0; v < nvars; ++v )
5437  {
5438  newlbs[v] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[v]));
5439  newubs[v] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[v]));
5440  lbinferinfos[v] = 0;
5441  ubinferinfos[v] = 0;
5442  }
5443 
5444  /* collect earliest start times, latest completion time, and free energy contributions */
5445  collectDataTTEF(scip, nvars, vars, durations, demands, hmin, hmax, permests, ests, permlcts, lcts, ects, lsts, flexenergies);
5446 
5447  /* sort the earliest start times and latest completion in non-decreasing order */
5448  SCIPsortIntInt(ests, permests, nvars);
5449  SCIPsortIntInt(lcts, permlcts, nvars);
5450 
5451  /* compute for the different earliest start and latest completion time the core energy of the corresponding time
5452  * points
5453  */
5454  computeCoreEnergyAfter(profile, nvars, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct);
5455 
5456  /* propagate the upper bounds and "opportunistically" the lower bounds */
5457  SCIP_CALL( propagateUbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5458  newlbs, newubs, lbinferinfos, ubinferinfos, lsts, flexenergies,
5459  permests, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5460 
5461  /* propagate the lower bounds and "opportunistically" the upper bounds */
5462  SCIP_CALL( propagateLbTTEF(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
5463  newlbs, newubs, lbinferinfos, ubinferinfos, ects, flexenergies,
5464  permlcts, ests, lcts, coreEnergyAfterEst, coreEnergyAfterLct, initialized, explanation, cutoff) );
5465 
5466  /* apply the buffer bound changes */
5467  for( v = 0; v < nvars && !(*cutoff); ++v )
5468  {
5469  SCIP_Bool infeasible;
5470  SCIP_Bool tightened;
5471 
5472  if( inferInfoIsValid(intToInferInfo(lbinferinfos[v])) )
5473  {
5474  SCIP_CALL( SCIPinferVarLbCons(scip, vars[v], (SCIP_Real)newlbs[v], cons, lbinferinfos[v],
5475  TRUE, &infeasible, &tightened) );
5476  }
5477  else
5478  {
5479  SCIP_CALL( SCIPtightenVarLb(scip, vars[v], (SCIP_Real)newlbs[v], TRUE, &infeasible, &tightened) );
5480  }
5481 
5482  /* since we change first the lower bound of the variable an infeasibilty should not be detected */
5483  assert(!infeasible);
5484 
5485  if( tightened )
5486  {
5487  (*nchgbds)++;
5488 
5489  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5491  }
5492 
5493  if( inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
5494  {
5495  SCIP_CALL( SCIPinferVarUbCons(scip, vars[v], (SCIP_Real)newubs[v], cons, ubinferinfos[v],
5496  TRUE, &infeasible, &tightened) );
5497  }
5498  else
5499  {
5500  SCIP_CALL( SCIPtightenVarUb(scip, vars[v], (SCIP_Real)newubs[v], TRUE, &infeasible, &tightened) );
5501  }
5502 
5503  /* since upper bound was compute w.r.t. the "old" bound the previous lower bound update together with this upper
5504  * bound update can be infeasible
5505  */
5506  if( infeasible )
5507  {
5508  /* a small performance improvement is possible here: if the tighten...TEFF and propagate...TEFF methods would
5509  * return not only the inferinfos, but the actual begin and end values, then the infeasibility here could also
5510  * be analyzed in the case when begin and end exceed the 15 bit limit
5511  */
5512  if( SCIPisConflictAnalysisApplicable(scip) && inferInfoIsValid(intToInferInfo(ubinferinfos[v])) )
5513  {
5514  INFERINFO inferinfo;
5515  SCIP_VAR* var;
5516  int begin;
5517  int end;
5518 
5519  var = vars[v];
5520  assert(var != NULL);
5521 
5522  /* initialize conflict analysis */
5524 
5525  /* convert int to inference information */
5526  inferinfo = intToInferInfo(ubinferinfos[v]);
5527 
5528  /* collect time window from inference information */
5529  begin = inferInfoGetData1(inferinfo);
5530  end = inferInfoGetData2(inferinfo);
5531  assert(begin < end);
5532 
5533  /* added to lower bound (which was undercut be new upper bound) of the variable */
5534  SCIP_CALL( SCIPaddConflictLb(scip, var, NULL) );
5535 
5536  /* analysis the upper bound change */
5537  SCIP_CALL( analyzeEnergyRequirement(scip, nvars, vars, durations, demands, capacity,
5538  begin, end, var, SCIP_BOUNDTYPE_UPPER, NULL, SCIPvarGetLbLocal(vars[v]) - 1.0,
5539  conshdlrdata->usebdwidening, explanation) );
5540 
5541  (*initialized) = TRUE;
5542  }
5543 
5544  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5545  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverloadTTEF++ );
5546 
5547  (*cutoff) = TRUE;
5548  break;
5549  }
5550 
5551  if( tightened )
5552  {
5553  (*nchgbds)++;
5554 
5555  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5557  }
5558  }
5559 
5560  SCIPfreeBufferArray(scip, &ubinferinfos);
5561  SCIPfreeBufferArray(scip, &lbinferinfos);
5562  SCIPfreeBufferArray(scip, &newubs);
5563  SCIPfreeBufferArray(scip, &newlbs);
5564 
5565  /* free buffer arrays */
5566  SCIPfreeBufferArray(scip, &lsts);
5567  SCIPfreeBufferArray(scip, &ects);
5568  SCIPfreeBufferArray(scip, &ests);
5569  SCIPfreeBufferArray(scip, &lcts);
5570  SCIPfreeBufferArray(scip, &permests);
5571  SCIPfreeBufferArray(scip, &permlcts);
5572  SCIPfreeBufferArray(scip, &flexenergies);
5573  SCIPfreeBufferArray(scip, &coreEnergyAfterLct);
5574  SCIPfreeBufferArray(scip, &coreEnergyAfterEst);
5575 
5576  return SCIP_OKAY;
5577 }
5578 
5579 /** a cumulative condition is not satisfied if its capacity is exceeded at a time where jobs cannot be shifted (core)
5580  * anymore we build up a cumulative profile of all cores of jobs and try to improve bounds of all jobs; also known as
5581  * time table propagator
5582  */
5583 static
5585  SCIP* scip, /**< SCIP data structure */
5586  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5587  SCIP_PROFILE* profile, /**< core profile */
5588  int nvars, /**< number of start time variables (activities) */
5589  SCIP_VAR** vars, /**< array of start time variables */
5590  int* durations, /**< array of durations */
5591  int* demands, /**< array of demands */
5592  int capacity, /**< cumulative capacity */
5593  int hmin, /**< left bound of time axis to be considered (including hmin) */
5594  int hmax, /**< right bound of time axis to be considered (not including hmax) */
5595  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
5596  int* nchgbds, /**< pointer to store the number of bound changes */
5597  SCIP_Bool* initialized, /**< was conflict analysis initialized */
5598  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
5599  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
5600  )
5601 {
5602  SCIP_Bool infeasible;
5603  int v;
5604 
5605  assert(scip != NULL);
5606  assert(nvars > 0);
5607  assert(cons != NULL);
5608  assert(cutoff != NULL);
5609 
5610  /* check if already a cutoff was detected */
5611  if( (*cutoff) )
5612  return SCIP_OKAY;
5613 
5614  /* check if the time tabling should infer bounds */
5615  if( !conshdlrdata->ttinfer )
5616  return SCIP_OKAY;
5617 
5618  assert(*initialized == FALSE);
5619 
5620  SCIPdebugMsg(scip, "propagate cores of cumulative condition of constraint <%s>[%d,%d) <= %d\n",
5621  SCIPconsGetName(cons), hmin, hmax, capacity);
5622 
5623  infeasible = FALSE;
5624 
5625  /* if core profile is empty; nothing to do */
5626  if( SCIPprofileGetNTimepoints(profile) <= 1 )
5627  return SCIP_OKAY;
5628 
5629  /* start checking each job whether the bounds can be improved */
5630  for( v = 0; v < nvars; ++v )
5631  {
5632  SCIP_VAR* var;
5633  int demand;
5634  int duration;
5635  int begin;
5636  int end;
5637  int est;
5638  int lst;
5639 
5640  var = vars[v];
5641  assert(var != NULL);
5642 
5643  duration = durations[v];
5644  assert(duration > 0);
5645 
5646  /* collect earliest and latest start time */
5647  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5648  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5649 
5650  /* check if the start time variables is already fixed; in that case we can ignore the job */
5651  if( est == lst )
5652  continue;
5653 
5654  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
5655  if( lst + duration <= hmin || est >= hmax )
5656  continue;
5657 
5658  /* compute core interval w.r.t. effective time horizon */
5659  begin = MAX(hmin, lst);
5660  end = MIN(hmax, est + duration);
5661 
5662  demand = demands[v];
5663  assert(demand > 0);
5664 
5665  /* if the job has a core, remove it first */
5666  if( begin < end )
5667  {
5668  SCIPdebugMsg(scip, "variable <%s>[%g,%g] (duration %d, demand %d): remove core [%d,%d)\n",
5669  SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), duration, demand, begin, end);
5670 
5671  SCIP_CALL( SCIPprofileDeleteCore(profile, begin, end, demand) );
5672  }
5673 
5674  /* first try to update the earliest start time */
5675  SCIP_CALL( coretimesUpdateLb(scip, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
5676  profile, v, nchgbds, conshdlrdata->usebdwidening, initialized, explanation, cutoff) );
5677 
5678  if( *cutoff )
5679  break;
5680 
5681  /* second try to update the latest start time */
5682  SCIP_CALL( coretimesUpdateUb(scip, var, duration, demand, capacity, cons,
5683  profile, v, nchgbds) );
5684 
5685  if( *cutoff )
5686  break;
5687 
5688  /* collect the potentially updated earliest and latest start time */
5689  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
5690  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
5691 
5692  /* compute core interval w.r.t. effective time horizon */
5693  begin = MAX(hmin, lst);
5694  end = MIN(hmax, est + duration);
5695 
5696  /* after updating the bound we might have a new core */
5697  if( begin < end )
5698  {
5699  int pos;
5700 
5701  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
5702  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
5703 
5704  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
5705 
5706  if( infeasible )
5707  {
5708  /* use conflict analysis to analysis the core insertion which was infeasible */
5709  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
5710  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
5711 
5712  if( explanation != NULL )
5713  explanation[v] = TRUE;
5714 
5715  (*cutoff) = TRUE;
5716 
5717  /* for the statistic we count the number of times a cutoff was detected due the time-time */
5718  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
5719 
5720  break;
5721  }
5722  }
5723  }
5724 
5725  return SCIP_OKAY;
5726 }
5727 
5728 
5729 /** node data structure for the binary tree used for edgefinding (with overload checking) */
5730 struct SCIP_NodeData
5731 {
5732  SCIP_VAR* var; /**< start time variable of the job if the node data belongs to a leaf, otherwise NULL */
5733  SCIP_Real key; /**< key which is to insert the corresponding search node */
5734  int est; /**< earliest start time if the node data belongs to a leaf */
5735  int lct; /**< latest completion time if the node data belongs to a leaf */
5736  int demand; /**< demand of the job if the node data belongs to a leaf */
5737  int duration; /**< duration of the job if the node data belongs to a leaf */
5738  int leftadjust; /**< left adjustments of the duration w.r.t. hmin */
5739  int rightadjust; /**< right adjustments of the duration w.r.t. hmax */
5740  SCIP_Longint enveloptheta; /**< the maximal energy of a subset of jobs part of the theta set */
5741  int energytheta; /**< energy of the subset of the jobs which are part of theta set */
5742  int energylambda;
5743  SCIP_Longint enveloplambda;
5744  int idx; /**< index of the start time variable in the (global) variable array */
5745  SCIP_Bool intheta; /**< belongs the node to the theta set (otherwise to the lambda set) */
5746 };
5747 typedef struct SCIP_NodeData SCIP_NODEDATA;
5749 
5750 /** update node data structure starting from the given node along the path to the root node */
5751 static
5752 void updateEnvelope(
5753  SCIP* scip, /**< SCIP data structure */
5754  SCIP_BTNODE* node /**< search node which inserted */
5755  )
5756 {
5757  SCIP_BTNODE* left;
5758  SCIP_BTNODE* right;
5759  SCIP_NODEDATA* nodedata;
5760  SCIP_NODEDATA* leftdata;
5761  SCIP_NODEDATA* rightdata;
5762 
5763  SCIPdebugMsg(scip, "update envelop starting from node <%p>\n", (void*)node);
5764 
5765  if( SCIPbtnodeIsLeaf(node) )
5766  node = SCIPbtnodeGetParent(node);
5767 
5768  while( node != NULL )
5769  {
5770  /* get node data */
5771  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5772  assert(nodedata != NULL);
5773 
5774  /* collect node data from left node */
5775  left = SCIPbtnodeGetLeftchild(node);
5776  assert(left != NULL);
5777  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
5778  assert(leftdata != NULL);
5779 
5780  /* collect node data from right node */
5781  right = SCIPbtnodeGetRightchild(node);
5782  assert(right != NULL);
5783  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
5784  assert(rightdata != NULL);
5785 
5786  /* update envelop and energy */
5787  if( leftdata->enveloptheta >= 0 )
5788  {
5789  assert(rightdata->energytheta != -1);
5790  nodedata->enveloptheta = MAX(leftdata->enveloptheta + rightdata->energytheta, rightdata->enveloptheta);
5791  }
5792  else
5793  nodedata->enveloptheta = rightdata->enveloptheta;
5794 
5795  assert(leftdata->energytheta != -1);
5796  assert(rightdata->energytheta != -1);
5797  nodedata->energytheta = leftdata->energytheta + rightdata->energytheta;
5798 
5799  if( leftdata->enveloplambda >= 0 )
5800  {
5801  assert(rightdata->energytheta != -1);
5802  nodedata->enveloplambda = MAX(leftdata->enveloplambda + rightdata->energytheta, rightdata->enveloplambda);
5803  }
5804  else
5805  nodedata->enveloplambda = rightdata->enveloplambda;
5806 
5807  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0 )
5808  nodedata->enveloplambda = MAX(nodedata->enveloplambda, leftdata->enveloptheta + rightdata->energylambda);
5809 
5810  SCIPdebugMsg(scip, "node <%p> lambda envelop %" SCIP_LONGINT_FORMAT "\n", (void*)node, nodedata->enveloplambda);
5811 
5812  if( leftdata->energylambda >= 0 && rightdata->energylambda >= 0 )
5813  {
5814  assert(rightdata->energytheta != -1);
5815  assert(leftdata->energytheta != -1);
5816  nodedata->energylambda = MAX(leftdata->energylambda + rightdata->energytheta, leftdata->energytheta + rightdata->energylambda);
5817  }
5818  else if( rightdata->energylambda >= 0 )
5819  {
5820  assert(leftdata->energytheta != -1);
5821  nodedata->energylambda = leftdata->energytheta + rightdata->energylambda;
5822  }
5823  else if( leftdata->energylambda >= 0 )
5824  {
5825  assert(rightdata->energytheta != -1);
5826  nodedata->energylambda = leftdata->energylambda + rightdata->energytheta;
5827  }
5828  else
5829  nodedata->energylambda = -1;
5830 
5831  /* go to parent */
5832  node = SCIPbtnodeGetParent(node);
5833  }
5834 
5835  SCIPdebugMsg(scip, "updating done\n");
5836 }
5837 
5838 /** updates the key of the first parent on the trace which comes from left */
5839 static
5840 void updateKeyOnTrace(
5841  SCIP_BTNODE* node, /**< node to start the trace */
5842  SCIP_Real key /**< update search key */
5843  )
5844 {
5845  assert(node != NULL);
5846 
5847  while( !SCIPbtnodeIsRoot(node) )
5848  {
5849  SCIP_BTNODE* parent;
5850 
5851  parent = SCIPbtnodeGetParent(node);
5852  assert(parent != NULL);
5853 
5854  if( SCIPbtnodeIsLeftchild(node) )
5855  {
5856  SCIP_NODEDATA* nodedata;
5857 
5858  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(parent);
5859  assert(nodedata != NULL);
5860 
5861  nodedata->key = key;
5862  return;
5863  }
5864 
5865  node = parent;
5866  }
5867 }
5868 
5869 
5870 /** deletes the given node and updates all envelops */
5871 static
5873  SCIP* scip, /**< SCIP data structure */
5874  SCIP_BT* tree, /**< binary tree */
5875  SCIP_BTNODE* node /**< node to be deleted */
5876  )
5877 {
5878  SCIP_BTNODE* parent;
5879  SCIP_BTNODE* grandparent;
5880  SCIP_BTNODE* sibling;
5881 
5882  assert(scip != NULL);
5883  assert(tree != NULL);
5884  assert(node != NULL);
5885 
5886  assert(SCIPbtnodeIsLeaf(node));
5887  assert(!SCIPbtnodeIsRoot(node));
5888 
5889  SCIPdebugMsg(scip, "delete node <%p>\n", (void*)node);
5890 
5891  parent = SCIPbtnodeGetParent(node);
5892  assert(parent != NULL);
5893  if( SCIPbtnodeIsLeftchild(node) )
5894  {
5895  sibling = SCIPbtnodeGetRightchild(parent);
5896  SCIPbtnodeSetRightchild(parent, NULL);
5897  }
5898  else
5899  {
5900  sibling = SCIPbtnodeGetLeftchild(parent);
5901  SCIPbtnodeSetLeftchild(parent, NULL);
5902  }
5903  assert(sibling != NULL);
5904 
5905  grandparent = SCIPbtnodeGetParent(parent);
5906 
5907  if( grandparent != NULL )
5908  {
5909  /* reset parent of sibling */
5910  SCIPbtnodeSetParent(sibling, grandparent);
5911 
5912  /* reset child of grandparent to sibling */
5913  if( SCIPbtnodeIsLeftchild(parent) )
5914  {
5915  SCIPbtnodeSetLeftchild(grandparent, sibling);
5916  }
5917  else
5918  {
5919  SCIP_NODEDATA* nodedata;
5920 
5921  assert(SCIPbtnodeIsRightchild(parent));
5922  SCIPbtnodeSetRightchild(grandparent, sibling);
5923 
5924  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(sibling);
5925 
5926  updateKeyOnTrace(grandparent, nodedata->key);
5927  }
5928 
5929  updateEnvelope(scip, grandparent);
5930  }
5931  else
5932  {
5933  SCIPbtnodeSetParent(sibling, NULL);
5934 
5935  SCIPbtSetRoot(tree, sibling);
5936  }
5937 
5938  SCIPbtnodeFree(tree, &parent);
5939 
5940  return SCIP_OKAY;
5941 }
5942 
5943 /** moves a node form the theta set into the lambda set and updates the envelops */
5944 static
5946  SCIP* scip, /**< SCIP data structure */
5947  SCIP_BT* tree, /**< binary tree */
5948  SCIP_BTNODE* node /**< node to move into the lambda set */
5949  )
5950 {
5951  SCIP_NODEDATA* nodedata;
5952 
5953  assert(scip != NULL);
5954  assert(tree != NULL);
5955  assert(node != NULL);
5956 
5957  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
5958  assert(nodedata != NULL);
5959  assert(nodedata->intheta);
5960 
5961  /* move the contributions form the theta set into the lambda set */
5962  assert(nodedata->enveloptheta != -1);
5963  assert(nodedata->energytheta != -1);
5964  assert(nodedata->enveloplambda == -1);
5965  assert(nodedata->energylambda == -1);
5966  nodedata->enveloplambda = nodedata->enveloptheta;
5967  nodedata->energylambda = nodedata->energytheta;
5968 
5969  nodedata->enveloptheta = -1;
5970  nodedata->energytheta = 0;
5971  nodedata->intheta = FALSE;
5972 
5973  /* update the energy and envelop values on trace */
5974  updateEnvelope(scip, node);
5975 
5976  return SCIP_OKAY;
5977 }
5978 
5979 /** inserts a node into the theta set and update the envelops */
5980 static
5982  SCIP* scip, /**< SCIP data structure */
5983  SCIP_BT* tree, /**< binary tree */
5984  SCIP_BTNODE* node, /**< node to insert */
5985  SCIP_NODEDATA* nodedatas, /**< array of node data */
5986  int* nodedataidx, /**< array of indices for node data */
5987  int* nnodedatas /**< pointer to number of node data */
5988  )
5989 {
5990  /* if the tree is empty the node will be the root node */
5991  if( SCIPbtIsEmpty(tree) )
5992  {
5993  SCIPbtSetRoot(tree, node);
5994  }
5995  else
5996  {
5997  SCIP_NODEDATA* newnodedata;
5998  SCIP_NODEDATA* leafdata;
5999  SCIP_NODEDATA* nodedata;
6000  SCIP_BTNODE* leaf;
6001  SCIP_BTNODE* newnode;
6002  SCIP_BTNODE* parent;
6003 
6004  leaf = SCIPbtGetRoot(tree);
6005  assert(leaf != NULL);
6006 
6007  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6008  assert(leafdata != NULL);
6009 
6010  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6011  assert(nodedata != NULL);
6012  assert(nodedata->intheta);
6013 
6014  /* find the position to insert the node */
6015  while( !SCIPbtnodeIsLeaf(leaf) )
6016  {
6017  if( nodedata->key < leafdata->key )
6018  leaf = SCIPbtnodeGetLeftchild(leaf);
6019  else
6020  leaf = SCIPbtnodeGetRightchild(leaf);
6021 
6022  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6023  assert(leafdata != NULL);
6024  }
6025 
6026  assert(leaf != NULL);
6027  assert(leaf != node);
6028 
6029  /* store node data to be able to delete them latter */
6030  newnodedata = &nodedatas[*nnodedatas];
6031  nodedataidx[*nnodedatas] = *nnodedatas;
6032  ++(*nnodedatas);
6033 
6034  /* init node data */
6035  newnodedata->var = NULL;
6036  newnodedata->key = SCIP_INVALID;
6037  newnodedata->est = INT_MIN;
6038  newnodedata->lct = INT_MAX;
6039  newnodedata->duration = 0;
6040  newnodedata->demand = 0;
6041  newnodedata->enveloptheta = -1;
6042  newnodedata->energytheta = 0;
6043  newnodedata->enveloplambda = -1;
6044  newnodedata->energylambda = -1;
6045  newnodedata->idx = -1;
6046  newnodedata->intheta = TRUE;
6047 
6048  /* create a new node */
6049  SCIP_CALL( SCIPbtnodeCreate(tree, &newnode, newnodedata) );
6050  assert(newnode != NULL);
6051 
6052  parent = SCIPbtnodeGetParent(leaf);
6053 
6054  if( parent != NULL )
6055  {
6056  SCIPbtnodeSetParent(newnode, parent);
6057 
6058  /* check if the node is the left child */
6059  if( SCIPbtnodeGetLeftchild(parent) == leaf )
6060  {
6061  SCIPbtnodeSetLeftchild(parent, newnode);
6062  }
6063  else
6064  {
6065  SCIPbtnodeSetRightchild(parent, newnode);
6066  }
6067  }
6068  else
6069  SCIPbtSetRoot(tree, newnode);
6070 
6071  if( nodedata->key < leafdata->key )
6072  {
6073  /* node is on the left */
6074  SCIPbtnodeSetLeftchild(newnode, node);
6075  SCIPbtnodeSetRightchild(newnode, leaf);
6076  newnodedata->key = nodedata->key;
6077  }
6078  else
6079  {
6080  /* leaf is on the left */
6081  SCIPbtnodeSetLeftchild(newnode, leaf);
6082  SCIPbtnodeSetRightchild(newnode, node);
6083  newnodedata->key = leafdata->key;
6084  }
6085 
6086  SCIPbtnodeSetParent(leaf, newnode);
6087  SCIPbtnodeSetParent(node, newnode);
6088  }
6089 
6090  /* update envelop */
6091  updateEnvelope(scip, node);
6092 
6093  return SCIP_OKAY;
6094 }
6095 
6096 /** returns the leaf responsible for the lambda energy */
6097 static
6099  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda energy */
6100  )
6101 {
6102  SCIP_BTNODE* left;
6103  SCIP_BTNODE* right;
6104  SCIP_NODEDATA* nodedata;
6105  SCIP_NODEDATA* leftdata;
6106  SCIP_NODEDATA* rightdata;
6107 
6108  assert(node != NULL);
6109 
6110  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6111  assert(nodedata != NULL);
6112 
6113  /* check if the node is the (responsible) leaf */
6114  if( SCIPbtnodeIsLeaf(node) )
6115  {
6116  assert(!nodedata->intheta);
6117  return node;
6118  }
6119 
6120  left = SCIPbtnodeGetLeftchild(node);
6121  assert(left != NULL);
6122 
6123  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6124  assert(leftdata != NULL);
6125 
6126  right = SCIPbtnodeGetRightchild(node);
6127  assert(right != NULL);
6128 
6129  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6130  assert(rightdata != NULL);
6131 
6132  assert(nodedata->energylambda != -1);
6133  assert(rightdata->energytheta != -1);
6134 
6135  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6137 
6138  assert(leftdata->energytheta != -1);
6139  assert(rightdata->energylambda != -1);
6140  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6141 
6143 }
6144 
6145 /** returns the leaf responsible for the lambda envelop */
6146 static
6148  SCIP_BTNODE* node /**< node which defines the subtree beases on the lambda envelop */
6149  )
6150 {
6151  SCIP_BTNODE* left;
6152  SCIP_BTNODE* right;
6153  SCIP_NODEDATA* nodedata;
6154  SCIP_NODEDATA* leftdata;
6155  SCIP_NODEDATA* rightdata;
6156 
6157  assert(node != NULL);
6158 
6159  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6160  assert(nodedata != NULL);
6161 
6162  /* check if the node is the (responsible) leaf */
6163  if( SCIPbtnodeIsLeaf(node) )
6164  {
6165  assert(!nodedata->intheta);
6166  return node;
6167  }
6168 
6169  left = SCIPbtnodeGetLeftchild(node);
6170  assert(left != NULL);
6171 
6172  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6173  assert(leftdata != NULL);
6174 
6175  right = SCIPbtnodeGetRightchild(node);
6176  assert(right != NULL);
6177 
6178  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6179  assert(rightdata != NULL);
6180 
6181  assert(nodedata->enveloplambda != -1);
6182  assert(rightdata->energytheta != -1);
6183 
6184  /* check if the left or right child is the one defining the envelop for the lambda set */
6185  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6187  else if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6188  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6190 
6191  assert(rightdata->enveloplambda != -1);
6192  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6193 
6195 }
6196 
6197 
6198 /** reports all elements from set theta to generate a conflicting set */
6199 static
6200 void collectThetaSubtree(
6201  SCIP_BTNODE* node, /**< node within a theta subtree */
6202  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6203  int* nelements, /**< pointer to store the number of elements in omegaset */
6204  int* est, /**< pointer to store the earliest start time of the omega set */
6205  int* lct, /**< pointer to store the latest start time of the omega set */
6206  int* energy /**< pointer to store the energy of the omega set */
6207  )
6208 {
6209  SCIP_NODEDATA* nodedata;
6210 
6211  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6212  assert(nodedata != NULL);
6213 
6214  if( !SCIPbtnodeIsLeaf(node) )
6215  {
6216  collectThetaSubtree(SCIPbtnodeGetLeftchild(node), omegaset, nelements, est, lct, energy);
6217  collectThetaSubtree(SCIPbtnodeGetRightchild(node), omegaset, nelements, est, lct, energy);
6218  }
6219  else if( nodedata->intheta )
6220  {
6221  assert(nodedata->var != NULL);
6222  SCIPdebugMessage("add variable <%s> as elements %d to omegaset\n", SCIPvarGetName(nodedata->var), *nelements);
6223 
6224  omegaset[*nelements] = node;
6225  (*est) = MIN(*est, nodedata->est);
6226  (*lct) = MAX(*lct, nodedata->lct);
6227  (*energy) += (nodedata->duration - nodedata->leftadjust - nodedata->rightadjust) * nodedata->demand;
6228  (*nelements)++;
6229  }
6230 }
6231 
6232 
6233 /** collect the jobs (omega set) which are contribute to theta envelop from the theta set */
6234 static
6235 void traceThetaEnvelop(
6236  SCIP_BTNODE* node, /**< node whose theta envelop needs to be backtracked */
6237  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6238  int* nelements, /**< pointer to store the number of elements in omegaset */
6239  int* est, /**< pointer to store the earliest start time of the omega set */
6240  int* lct, /**< pointer to store the latest start time of the omega set */
6241  int* energy /**< pointer to store the energy of the omega set */
6242  )
6243 {
6244  assert(node != NULL);
6245 
6246  if( SCIPbtnodeIsLeaf(node) )
6247  {
6248  collectThetaSubtree(node, omegaset, nelements, est, lct, energy);
6249  }
6250  else
6251  {
6252  SCIP_BTNODE* left;
6253  SCIP_BTNODE* right;
6254  SCIP_NODEDATA* nodedata;
6255  SCIP_NODEDATA* leftdata;
6256  SCIP_NODEDATA* rightdata;
6257 
6258  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6259  assert(nodedata != NULL);
6260 
6261  left = SCIPbtnodeGetLeftchild(node);
6262  assert(left != NULL);
6263 
6264  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6265  assert(leftdata != NULL);
6266 
6267  right = SCIPbtnodeGetRightchild(node);
6268  assert(right != NULL);
6269 
6270  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6271  assert(rightdata != NULL);
6272 
6273  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6274  assert(nodedata != NULL);
6275 
6276  assert(nodedata->enveloptheta != -1);
6277  assert(rightdata->energytheta != -1);
6278 
6279  if( leftdata->enveloptheta >= 0 && nodedata->enveloptheta == leftdata->enveloptheta + rightdata->energytheta )
6280  {
6281  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6282  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6283  }
6284  else
6285  {
6286  assert(rightdata->enveloptheta != -1);
6287  assert(nodedata->enveloptheta == rightdata->enveloptheta);
6288  traceThetaEnvelop(right, omegaset, nelements, est, lct, energy);
6289  }
6290  }
6291 }
6292 
6293 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6294 static
6295 void traceLambdaEnergy(
6296  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6297  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6298  int* nelements, /**< pointer to store the number of elements in omega set */
6299  int* est, /**< pointer to store the earliest start time of the omega set */
6300  int* lct, /**< pointer to store the latest start time of the omega set */
6301  int* energy /**< pointer to store the energy of the omega set */
6302  )
6303 {
6304  SCIP_BTNODE* left;
6305  SCIP_BTNODE* right;
6306  SCIP_NODEDATA* nodedata;
6307  SCIP_NODEDATA* leftdata;
6308  SCIP_NODEDATA* rightdata;
6309 
6310  assert(node != NULL);
6311 
6312  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6313  assert(nodedata != NULL);
6314 
6315  /* check if the node is a leaf */
6316  if( SCIPbtnodeIsLeaf(node) )
6317  return;
6318 
6319  left = SCIPbtnodeGetLeftchild(node);
6320  assert(left != NULL);
6321 
6322  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6323  assert(leftdata != NULL);
6324 
6325  right = SCIPbtnodeGetRightchild(node);
6326  assert(right != NULL);
6327 
6328  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6329  assert(rightdata != NULL);
6330 
6331  assert(nodedata->energylambda != -1);
6332  assert(rightdata->energytheta != -1);
6333 
6334  if( leftdata->energylambda >= 0 && nodedata->energylambda == leftdata->energylambda + rightdata->energytheta )
6335  {
6336  traceLambdaEnergy(left, omegaset, nelements, est, lct, energy);
6337  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6338  }
6339  else
6340  {
6341  assert(leftdata->energytheta != -1);
6342  assert(rightdata->energylambda != -1);
6343  assert(nodedata->energylambda == leftdata->energytheta + rightdata->energylambda);
6344 
6345  collectThetaSubtree(left, omegaset, nelements, est, lct, energy);
6346  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6347  }
6348 }
6349 
6350 /** collect the jobs (omega set) which are contribute to lambda envelop from the theta set */
6351 static
6352 void traceLambdaEnvelop(
6353  SCIP_BTNODE* node, /**< node whose lambda envelop needs to be backtracked */
6354  SCIP_BTNODE** omegaset, /**< array to store the collected jobs */
6355  int* nelements, /**< pointer to store the number of elements in omega set */
6356  int* est, /**< pointer to store the earliest start time of the omega set */
6357  int* lct, /**< pointer to store the latest start time of the omega set */
6358  int* energy /**< pointer to store the energy of the omega set */
6359  )
6360 {
6361  SCIP_BTNODE* left;
6362  SCIP_BTNODE* right;
6363  SCIP_NODEDATA* nodedata;
6364  SCIP_NODEDATA* leftdata;
6365  SCIP_NODEDATA* rightdata;
6366 
6367  assert(node != NULL);
6368 
6369  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6370  assert(nodedata != NULL);
6371 
6372  /* check if the node is a leaf */
6373  if( SCIPbtnodeIsLeaf(node) )
6374  {
6375  assert(!nodedata->intheta);
6376  return;
6377  }
6378 
6379  left = SCIPbtnodeGetLeftchild(node);
6380  assert(left != NULL);
6381 
6382  leftdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(left);
6383  assert(leftdata != NULL);
6384 
6385  right = SCIPbtnodeGetRightchild(node);
6386  assert(right != NULL);
6387 
6388  rightdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(right);
6389  assert(rightdata != NULL);
6390 
6391  assert(nodedata->enveloplambda != -1);
6392  assert(rightdata->energytheta != -1);
6393 
6394  if( leftdata->enveloplambda >= 0 && nodedata->enveloplambda == leftdata->enveloplambda + rightdata->energytheta )
6395  {
6396  traceLambdaEnvelop(left, omegaset, nelements, est, lct, energy);
6397  collectThetaSubtree(right, omegaset, nelements, est, lct, energy);
6398  }
6399  else
6400  {
6401  if( leftdata->enveloptheta >= 0 && rightdata->energylambda >= 0
6402  && nodedata->enveloplambda == leftdata->enveloptheta + rightdata->energylambda )
6403  {
6404  traceThetaEnvelop(left, omegaset, nelements, est, lct, energy);
6405  traceLambdaEnergy(right, omegaset, nelements, est, lct, energy);
6406  }
6407  else
6408  {
6409  assert(rightdata->enveloplambda != -1);
6410  assert(nodedata->enveloplambda == rightdata->enveloplambda);
6411  traceLambdaEnvelop(right, omegaset, nelements, est, lct, energy);
6412  }
6413  }
6414 }
6415 
6416 /** compute the energy contribution by job which corresponds to the given leaf */
6417 static
6419  SCIP_BTNODE* node /**< leaf */
6420  )
6421 {
6422  SCIP_NODEDATA* nodedata;
6423  int duration;
6424 
6425  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(node);
6426  assert(nodedata != NULL);
6427  assert(nodedata->var != NULL);
6428 
6429  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
6430  assert(duration > 0);
6431 
6432  SCIPdebugMessage("variable <%s>: loc=[%g,%g] glb=[%g,%g] (duration %d, demand %d)\n",
6434  SCIPvarGetLbGlobal(nodedata->var), SCIPvarGetUbGlobal(nodedata->var), duration, nodedata->demand);
6435 
6436  /* return energy which is contributed by the start time variable */
6437  return nodedata->demand * duration;
6438 }
6439 
6440 /** comparison method for two node data w.r.t. the earliest start time */
6441 static
6442 SCIP_DECL_SORTPTRCOMP(compNodeEst)
6444  int est1;
6445  int est2;
6446 
6447  est1 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem1))->est;
6448  est2 = ((SCIP_NODEDATA*)SCIPbtnodeGetData((SCIP_BTNODE*)elem2))->est;
6449 
6450  return (est1 - est2);
6451 }
6452 
6453 /** comparison method for two node data w.r.t. the latest completion time */
6454 static
6455 SCIP_DECL_SORTINDCOMP(compNodedataLct)
6457  SCIP_NODEDATA* nodedatas;
6458 
6459  nodedatas = (SCIP_NODEDATA*) dataptr;
6460  return (nodedatas[ind1].lct - nodedatas[ind2].lct);
6461 }
6462 
6463 
6464 /** an overload was detected; initialized conflict analysis, add an initial reason
6465  *
6466  * @note the conflict analysis is not performend, only the initialized SCIP_Bool pointer is set to TRUE
6467  */
6468 static
6470  SCIP* scip, /**< SCIP data structure */
6471  SCIP_BTNODE** leaves, /**< responsible leaves for the overload */
6472  int capacity, /**< cumulative capacity */
6473  int nleaves, /**< number of responsible leaves */
6474  int est, /**< earliest start time of the ...... */
6475  int lct, /**< latest completly time of the .... */
6476  int reportedenergy, /**< energy which already reported */
6477  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6478  int shift, /**< shift applied to all jobs before adding them to the tree */
6479  SCIP_Bool usebdwidening, /**< should bound widening be used during conflict analysis? */
6480  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6481  SCIP_Bool* explanation /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6482  )
6483 {
6484  SCIP_Longint energy;
6485  int j;
6486 
6487  /* do nothing if conflict analysis is not applicable */
6489  return SCIP_OKAY;
6490 
6491  SCIPdebugMsg(scip, "est=%d, lct=%d, propest %u, reportedenergy %d, shift %d\n", est, lct, propest, reportedenergy, shift);
6492 
6493  /* compute energy of initial time window */
6494  energy = ((SCIP_Longint) lct - est) * capacity;
6495 
6496  /* sort the start time variables which were added to search tree w.r.t. earliest start time */
6497  SCIPsortDownPtr((void**)leaves, compNodeEst, nleaves);
6498 
6499  /* collect the energy of the responsible leaves until the cumulative energy is large enough to detect an overload;
6500  * thereby, compute the time window of interest
6501  */
6502  for( j = 0; j < nleaves && reportedenergy <= energy; ++j )
6503  {
6504  SCIP_NODEDATA* nodedata;
6505 
6506  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6507  assert(nodedata != NULL);
6508 
6509  reportedenergy += computeEnergyContribution(leaves[j]);
6510 
6511  /* adjust energy if the earliest start time decrease */
6512  if( nodedata->est < est )
6513  {
6514  est = nodedata->est;
6515  energy = ((SCIP_Longint) lct - est) * capacity;
6516  }
6517  }
6518  assert(reportedenergy > energy);
6519 
6520  SCIPdebugMsg(scip, "time window [%d,%d) available energy %" SCIP_LONGINT_FORMAT ", required energy %d\n", est, lct, energy, reportedenergy);
6521 
6522  /* initialize conflict analysis */
6524 
6525  /* flip earliest start time and latest completion time */
6526  if( !propest )
6527  {
6528  SCIPswapInts(&est, &lct);
6529 
6530  /* shift earliest start time and latest completion time */
6531  lct = shift - lct;
6532  est = shift - est;
6533  }
6534  else
6535  {
6536  /* shift earliest start time and latest completion time */
6537  lct = lct + shift;
6538  est = est + shift;
6539  }
6540 
6541  nleaves = j;
6542 
6543  /* report the variables and relax their bounds to final time interval [est,lct) which was been detected to be
6544  * overloaded
6545  */
6546  for( j = nleaves-1; j >= 0; --j )
6547  {
6548  SCIP_NODEDATA* nodedata;
6549 
6550  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6551  assert(nodedata != NULL);
6552  assert(nodedata->var != NULL);
6553 
6554  /* check if bound widening should be used */
6555  if( usebdwidening )
6556  {
6557  SCIP_CALL( SCIPaddConflictRelaxedUb(scip, nodedata->var, NULL, (SCIP_Real)(est - nodedata->leftadjust)) );
6558  SCIP_CALL( SCIPaddConflictRelaxedLb(scip, nodedata->var, NULL, (SCIP_Real)(lct - nodedata->duration + nodedata->rightadjust)) );
6559  }
6560  else
6561  {
6562  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6563  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6564  }
6565 
6566  if( explanation != NULL )
6567  explanation[nodedata->idx] = TRUE;
6568  }
6569 
6570  (*initialized) = TRUE;
6571 
6572  return SCIP_OKAY;
6573 }
6574 
6575 /** computes a new latest starting time of the job in 'respleaf' due to the energy consumption and stores the
6576  * responsible interval bounds in *est_omega and *lct_omega
6577  */
6578 static
6579 int computeEstOmegaset(
6580  SCIP* scip, /**< SCIP data structure */
6581  int duration, /**< duration of the job to move */
6582  int demand, /**< demand of the job to move */
6583  int capacity, /**< cumulative capacity */
6584  int est, /**< earliest start time of the omega set */
6585  int lct, /**< latest start time of the omega set */
6586  int energy /**< energy of the omega set */
6587  )
6588 {
6589  int newest;
6590 
6591  newest = 0;
6592 
6593  assert(scip != NULL);
6594 
6595  if( energy > ((SCIP_Longint) capacity - demand) * ((SCIP_Longint) lct - est) )
6596  {
6597  if( energy + (SCIP_Longint) demand * duration > capacity * ((SCIP_Longint) lct - est) )
6598  {
6599  newest = (int)SCIPfeasCeil(scip, (energy - (SCIP_Real)(capacity - demand) * (lct - est)) / (SCIP_Real)demand);
6600  newest += est;
6601  }
6602  }
6603 
6604  return newest;
6605 }
6606 
6607 /** propagates start time using an edge finding algorithm which is based on binary trees (theta lambda trees)
6608  *
6609  * @note The algorithm is based on the paper: Petr Vilim, "Edge Finding Filtering Algorithm for Discrete Cumulative
6610  * Resources in O(kn log n)". *I.P. Gent (Ed.): CP 2009, LNCS 5732, pp. 802-816, 2009.
6611  */
6612 static
6614  SCIP* scip, /**< SCIP data structure */
6615  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6616  SCIP_CONS* cons, /**< constraint which is propagated */
6617  SCIP_BT* tree, /**< binary tree constaining the theta and lambda sets */
6618  SCIP_BTNODE** leaves, /**< array of all leaves for each job one */
6619  int capacity, /**< cumulative capacity */
6620  int ncands, /**< number of candidates */
6621  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6622  int shift, /**< shift applied to all jobs before adding them to the tree */
6623  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6624  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6625  int* nchgbds, /**< pointer to store the number of bound changes */
6626  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6627  )
6628 {
6629  SCIP_NODEDATA* rootdata;
6630  int j;
6631 
6632  assert(!SCIPbtIsEmpty(tree));
6633 
6634  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6635  assert(rootdata != NULL);
6636 
6637  /* iterate over all added candidate (leaves) in non-increasing order w.r.t. their latest completion time */
6638  for( j = ncands-1; j >= 0 && !(*cutoff); --j )
6639  {
6640  SCIP_NODEDATA* nodedata;
6641 
6642  if( SCIPbtnodeIsRoot(leaves[j]) )
6643  break;
6644 
6645  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaves[j]);
6646  assert(nodedata->est != -1);
6647 
6648  /* check if the root lambda envelop exeeds the available capacity */
6649  while( !(*cutoff) && rootdata->enveloplambda > (SCIP_Longint) capacity * nodedata->lct )
6650  {
6651  SCIP_BTNODE** omegaset;
6652  SCIP_BTNODE* leaf;
6653  SCIP_NODEDATA* leafdata;
6654  int nelements;
6655  int energy;
6656  int newest;
6657  int est;
6658  int lct;
6659 
6660  assert(!(*cutoff));
6661 
6662  /* find responsible leaf for the lambda envelope */
6664  assert(leaf != NULL);
6665  assert(SCIPbtnodeIsLeaf(leaf));
6666 
6667  leafdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(leaf);
6668  assert(leafdata != NULL);
6669  assert(!leafdata->intheta);
6670  assert(leafdata->duration > 0);
6671  assert(leafdata->est >= 0);
6672 
6673  /* check if the job has to be removed since its latest completion is to large */
6674  if( leafdata->est + leafdata->duration >= nodedata->lct )
6675  {
6676  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6677 
6678  /* the root might changed therefore we need to collect the new root node data */
6679  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6680  assert(rootdata != NULL);
6681 
6682  continue;
6683  }
6684 
6685  /* compute omega set */
6686  SCIP_CALL( SCIPallocBufferArray(scip, &omegaset, ncands) );
6687 
6688  nelements = 0;
6689  est = INT_MAX;
6690  lct = INT_MIN;
6691  energy = 0;
6692 
6693  /* collect the omega set from theta set */
6694  traceLambdaEnvelop(SCIPbtGetRoot(tree), omegaset, &nelements, &est, &lct, &energy);
6695  assert(nelements > 0);
6696  assert(nelements < ncands);
6697 
6698  newest = computeEstOmegaset(scip, leafdata->duration, leafdata->demand, capacity, est, lct, energy);
6699 
6700  /* if the computed earliest start time is greater than the latest completion time of the omega set we detected an overload */
6701  if( newest > lct )
6702  {
6703  SCIPdebugMsg(scip, "an overload was detected duration edge-finder propagattion\n");
6704 
6705  /* analyze over load */
6706  SCIP_CALL( analyzeConflictOverload(scip, omegaset, capacity, nelements, est, lct, 0, propest, shift,
6707  conshdlrdata->usebdwidening, initialized, explanation) );
6708  (*cutoff) = TRUE;
6709 
6710  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6711  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6712  }
6713  else if( newest > 0 )
6714  {
6715  SCIP_Bool infeasible;
6716  SCIP_Bool tightened;
6717  INFERINFO inferinfo;
6718 
6719  if( propest )
6720  {
6721  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6722  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, est + shift, lct + shift);
6723 
6724  SCIPdebugMsg(scip, "variable <%s> adjust lower bound from %g to %d\n",
6725  SCIPvarGetName(leafdata->var), SCIPvarGetLbLocal(leafdata->var), newest + shift);
6726 
6727  if( inferInfoIsValid(inferinfo) )
6728  {
6729  SCIP_CALL( SCIPinferVarLbCons(scip, leafdata->var, (SCIP_Real)(newest + shift),
6730  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6731  }
6732  else
6733  {
6734  SCIP_CALL( SCIPtightenVarLb(scip, leafdata->var, (SCIP_Real)(newest + shift),
6735  TRUE, &infeasible, &tightened) );
6736  }
6737 
6738  /* for the statistic we count the number of times a lower bound was tightened due the edge-finder */
6740  }
6741  else
6742  {
6743  /* constuct inference information; store used propagation rule and the the time window of the omega set */
6744  inferinfo = getInferInfo(PROPRULE_2_EDGEFINDING, shift - lct, shift - est);
6745 
6746  SCIPdebugMsg(scip, "variable <%s> adjust upper bound from %g to %d\n",
6747  SCIPvarGetName(leafdata->var), SCIPvarGetUbLocal(leafdata->var), shift - newest - leafdata->duration);
6748 
6749  if( inferInfoIsValid(inferinfo) )
6750  {
6751  SCIP_CALL( SCIPinferVarUbCons(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6752  cons, inferInfoToInt(inferinfo), TRUE, &infeasible, &tightened) );
6753  }
6754  else
6755  {
6756  SCIP_CALL( SCIPtightenVarUb(scip, leafdata->var, (SCIP_Real)(shift - newest - leafdata->duration),
6757  TRUE, &infeasible, &tightened) );
6758  }
6759 
6760  /* for the statistic we count the number of times a upper bound was tightened due the edge-finder */
6762  }
6763 
6764  /* adjust the earliest start time */
6765  if( tightened )
6766  {
6767  leafdata->est = newest;
6768  (*nchgbds)++;
6769  }
6770 
6771  if( infeasible )
6772  {
6773  /* initialize conflict analysis if conflict analysis is applicable */
6775  {
6776  int i;
6777 
6778  SCIPdebugMsg(scip, "edge-finder dectected an infeasibility\n");
6779 
6781 
6782  /* add lower and upper bound of variable which leads to the infeasibilty */
6783  SCIP_CALL( SCIPaddConflictLb(scip, leafdata->var, NULL) );
6784  SCIP_CALL( SCIPaddConflictUb(scip, leafdata->var, NULL) );
6785 
6786  if( explanation != NULL )
6787  explanation[leafdata->idx] = TRUE;
6788 
6789  /* add lower and upper bound of variable which lead to the infeasibilty */
6790  for( i = 0; i < nelements; ++i )
6791  {
6792  nodedata = (SCIP_NODEDATA*)SCIPbtnodeGetData(omegaset[i]);
6793  assert(nodedata != NULL);
6794 
6795  SCIP_CALL( SCIPaddConflictLb(scip, nodedata->var, NULL) );
6796  SCIP_CALL( SCIPaddConflictUb(scip, nodedata->var, NULL) );
6797 
6798  if( explanation != NULL )
6799  explanation[nodedata->idx] = TRUE;
6800  }
6801 
6802  (*initialized) = TRUE;
6803  }
6804 
6805  (*cutoff) = TRUE;
6806 
6807  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
6808  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffedgefinder++ );
6809  }
6810  }
6811 
6812  /* free omegaset array */
6813  SCIPfreeBufferArray(scip, &omegaset);
6814 
6815  /* delete responsible leaf from lambda */
6816  SCIP_CALL( deleteLambdaLeaf(scip, tree, leaf) );
6817 
6818  /* the root might changed therefore we need to collect the new root node data */
6819  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
6820  assert(rootdata != NULL);
6821  }
6822 
6823  /* move current job j from the theta set into the lambda set */
6824  SCIP_CALL( moveNodeToLambda(scip, tree, leaves[j]) );
6825  }
6826 
6827  return SCIP_OKAY;
6828 }
6829 
6830 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
6831  *
6832  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
6833  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
6834  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
6835  */
6836 static
6838  SCIP* scip, /**< SCIP data structure */
6839  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6840  int nvars, /**< number of start time variables (activities) */
6841  SCIP_VAR** vars, /**< array of start time variables */
6842  int* durations, /**< array of durations */
6843  int* demands, /**< array of demands */
6844  int capacity, /**< cumulative capacity */
6845  int hmin, /**< left bound of time axis to be considered (including hmin) */
6846  int hmax, /**< right bound of time axis to be considered (not including hmax) */
6847  SCIP_CONS* cons, /**< constraint which is propagated */
6848  SCIP_Bool propest, /**< should the earliest start times be propagated, otherwise the latest completion times */
6849  SCIP_Bool* initialized, /**< was conflict analysis initialized */
6850  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
6851  int* nchgbds, /**< pointer to store the number of bound changes */
6852  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
6853  )
6854 {
6855  SCIP_NODEDATA* nodedatas;
6856  SCIP_BTNODE** leaves;
6857  SCIP_BT* tree;
6858  int* nodedataidx;
6859 
6860  int totalenergy;
6861  int nnodedatas;
6862  int ninsertcands;
6863  int ncands;
6864 
6865  int shift;
6866  int idx = -1;
6867  int j;
6868 
6869  assert(scip != NULL);
6870  assert(cons != NULL);
6871  assert(initialized != NULL);
6872  assert(cutoff != NULL);
6873  assert(*cutoff == FALSE);
6874 
6875  SCIPdebugMsg(scip, "check overload of cumulative condition of constraint <%s> (capacity %d)\n", SCIPconsGetName(cons), capacity);
6876 
6877  SCIP_CALL( SCIPallocBufferArray(scip, &nodedatas, 2*nvars) );
6878  SCIP_CALL( SCIPallocBufferArray(scip, &nodedataidx, 2*nvars) );
6879  SCIP_CALL( SCIPallocBufferArray(scip, &leaves, nvars) );
6880 
6881  ncands = 0;
6882  totalenergy = 0;
6883 
6884  SCIP_CALL( SCIPbtCreate(&tree, SCIPblkmem(scip)) );
6885 
6886  /* compute the shift which we apply to compute .... latest completion time of all jobs */
6887  if( propest )
6888  shift = 0;
6889  else
6890  {
6891  shift = 0;
6892 
6893  /* compute the latest completion time of all jobs which define the shift we apply to run the algorithm for the
6894  * earliest start time propagation to handle the latest completion times
6895  */
6896  for( j = 0; j < nvars; ++j )
6897  {
6898  int lct;
6899 
6900  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + durations[j];
6901  shift = MAX(shift, lct);
6902  }
6903  }
6904 
6905  /* collect earliest and latest completion times and ignore jobs which do not run completion within the effective
6906  * horizon
6907  */
6908  for( j = 0; j < nvars; ++j )
6909  {
6910  SCIP_NODEDATA* nodedata;
6911  SCIP_VAR* var;
6912  int duration;
6913  int leftadjust;
6914  int rightadjust;
6915  int energy;
6916  int est;
6917  int lct;
6918 
6919  var = vars[j];
6920  assert(var != NULL);
6921 
6922  duration = durations[j];
6923  assert(duration > 0);
6924 
6925  leftadjust = 0;
6926  rightadjust = 0;
6927 
6928  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
6929  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
6930 
6931  /* adjust the duration, earliest start time, and latest completion time of jobs which do not lie completely in the
6932  * effective horizon [hmin,hmax)
6933  */
6934  if( conshdlrdata->useadjustedjobs )
6935  {
6936  if( est < hmin )
6937  {
6938  leftadjust = (hmin - est);
6939  est = hmin;
6940  }
6941  if( lct > hmax )
6942  {
6943  rightadjust = (lct - hmax);
6944  lct = hmax;
6945  }
6946 
6947  /* only consider jobs which have a (adjusted) duration greater than zero (the amound which will run defenetly
6948  * with the effective time horizon
6949  */
6950  if( duration - leftadjust - rightadjust <= 0 )
6951  continue;
6952  }
6953  else if( est < hmin || lct > hmax )
6954  continue;
6955 
6956  energy = demands[j] * (duration - leftadjust - rightadjust);
6957  assert(energy > 0);
6958 
6959  totalenergy += energy;
6960 
6961  /* flip earliest start time and latest completion time */
6962  if( !propest )
6963  {
6964  SCIPswapInts(&est, &lct);
6965 
6966  /* shift earliest start time and latest completion time */
6967  lct = shift - lct;
6968  est = shift - est;
6969  }
6970  else
6971  {
6972  /* shift earliest start time and latest completion time */
6973  lct = lct - shift;
6974  est = est - shift;
6975  }
6976  assert(est < lct);
6977  assert(est >= 0);
6978  assert(lct >= 0);
6979 
6980  /* create search node data */
6981  nodedata = &nodedatas[ncands];
6982  nodedataidx[ncands] = ncands;
6983  ++ncands;
6984 
6985  /* initialize search node data */
6986  /* adjust earliest start time to make it unique in case several jobs have the same earliest start time */
6987  nodedata->key = est + j / (2.0 * nvars);
6988  nodedata->var = var;
6989  nodedata->est = est;
6990  nodedata->lct = lct;
6991  nodedata->demand = demands[j];
6992  nodedata->duration = duration;
6993  nodedata->leftadjust = leftadjust;
6994  nodedata->rightadjust = rightadjust;
6995 
6996  /* the envelop is the energy of the job plus the total amount of energy which is available in the time period
6997  * before that job can start, that is [0,est). The envelop is later used to compare the energy consumption of a
6998  * particular time interval [a,b] against the time interval [0,b].
6999  */
7000  nodedata->enveloptheta = (SCIP_Longint) capacity * est + energy;
7001  nodedata->energytheta = energy;
7002  nodedata->enveloplambda = -1;
7003  nodedata->energylambda = -1;
7004 
7005  nodedata->idx = j;
7006  nodedata->intheta = TRUE;
7007  }
7008 
7009  nnodedatas = ncands;
7010 
7011  /* sort (non-decreasing) the jobs w.r.t. latest completion times */
7012  SCIPsortInd(nodedataidx, compNodedataLct, (void*)nodedatas, ncands);
7013 
7014  ninsertcands = 0;
7015 
7016  /* iterate over all jobs in non-decreasing order of their latest completion times and add them to the theta set until
7017  * the root envelop detects an overload
7018  */
7019  for( j = 0; j < ncands; ++j )
7020  {
7021  SCIP_BTNODE* leaf;
7022  SCIP_NODEDATA* rootdata;
7023 
7024  idx = nodedataidx[j];
7025 
7026  /* check if the new job opens a time window which size is so large that it offers more energy than the total
7027  * energy of all candidate jobs. If so we skip that one.
7028  */
7029  if( ((SCIP_Longint) nodedatas[idx].lct - nodedatas[idx].est) * capacity >= totalenergy )
7030  {
7031  /* set the earliest start time to minus one to mark that candidate to be not used */
7032  nodedatas[idx].est = -1;
7033  continue;
7034  }
7035 
7036  /* create search node */
7037  SCIP_CALL( SCIPbtnodeCreate(tree, &leaf, (void*)&nodedatas[idx]) );
7038 
7039  /* insert new node into the theta set and updete the envelops */
7040  SCIP_CALL( insertThetanode(scip, tree, leaf, nodedatas, nodedataidx, &nnodedatas) );
7041  assert(nnodedatas <= 2*nvars);
7042 
7043  /* move the inserted candidates together */
7044  leaves[ninsertcands] = leaf;
7045  ninsertcands++;
7046 
7047  assert(!SCIPbtIsEmpty(tree));
7048  rootdata = (SCIP_NODEDATA*)SCIPbtnodeGetData(SCIPbtGetRoot(tree));
7049  assert(rootdata != NULL);
7050 
7051  /* check if the theta set envelops exceeds the available capacity */
7052  if( rootdata->enveloptheta > (SCIP_Longint) capacity * nodedatas[idx].lct )
7053  {
7054  SCIPdebugMsg(scip, "detects cutoff due to overload in time window [?,%d) (ncands %d)\n", nodedatas[idx].lct, j);
7055  (*cutoff) = TRUE;
7056 
7057  /* for the statistic we count the number of times a cutoff was detected due the edge-finder */
7058  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutoffoverload++ );
7059 
7060  break;
7061  }
7062  }
7063 
7064  /* in case an overload was detected and the conflict analysis is applicable, create an initialize explanation */
7065  if( *cutoff )
7066  {
7067  int glbenery;
7068  int est;
7069  int lct;
7070 
7071  glbenery = 0;
7072  assert( 0 <= idx );
7073  est = nodedatas[idx].est;
7074  lct = nodedatas[idx].lct;
7075 
7076  /* scan the remaining candidates for a global contributions within the time window of the last inserted candidate
7077  * which led to an overload
7078  */
7079  for( j = j+1; j < ncands; ++j )
7080  {
7081  SCIP_NODEDATA* nodedata;
7082  int duration;
7083  int glbest;
7084  int glblct;
7085 
7086  idx = nodedataidx[j];
7087  nodedata = &nodedatas[idx];
7088  assert(nodedata != NULL);
7089 
7090  duration = nodedata->duration - nodedata->leftadjust - nodedata->rightadjust;
7091 
7092  /* get latest start time */
7093  glbest = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(nodedata->var));
7094  glblct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(nodedata->var)) + duration;
7095 
7096  /* check if parts of the jobs run with the time window defined by the last inserted job */
7097  if( glbest < est )
7098  duration -= (est - glbest);
7099 
7100  if( glblct > lct )
7101  duration -= (glblct - lct);
7102 
7103  if( duration > 0 )
7104  {
7105  glbenery += nodedata->demand * duration;
7106 
7107  if( explanation != NULL )
7108  explanation[nodedata->idx] = TRUE;
7109  }
7110  }
7111 
7112  /* analyze the overload */
7113  SCIP_CALL( analyzeConflictOverload(scip, leaves, capacity, ninsertcands, est, lct, glbenery, propest, shift,
7114  conshdlrdata->usebdwidening, initialized, explanation) );
7115  }
7116  else if( ninsertcands > 1 && conshdlrdata->efinfer )
7117  {
7118  /* if we have more than one job insterted and edge-finding should be performed we do it */
7119  SCIP_CALL( inferboundsEdgeFinding(scip, conshdlrdata, cons, tree, leaves, capacity, ninsertcands,
7120  propest, shift, initialized, explanation, nchgbds, cutoff) );
7121  }
7122 
7123  /* free theta tree */
7124  SCIPbtFree(&tree);
7125 
7126  /* free buffer arrays */
7127  SCIPfreeBufferArray(scip, &leaves);
7128  SCIPfreeBufferArray(scip, &nodedataidx);
7129  SCIPfreeBufferArray(scip, &nodedatas);
7130 
7131  return SCIP_OKAY;
7132 }
7133 
7134 /** checks whether the instance is infeasible due to a overload within a certain time frame using the idea of theta trees
7135  *
7136  * @note The algorithm is based on the paper: Petr Vilim, "Max Energy Filtering Algorithm for Discrete Cumulative
7137  * Resources". In: Willem Jan van Hoeve and John N. Hooker (Eds.), Integration of AI and OR Techniques in
7138  * Constraint Programming for Combinatorial Optimization Problems (CPAIOR 2009), LNCS 5547, pp 294--308
7139  */
7140 static
7142  SCIP* scip, /**< SCIP data structure */
7143  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7144  int nvars, /**< number of start time variables (activities) */
7145  SCIP_VAR** vars, /**< array of start time variables */
7146  int* durations, /**< array of durations */
7147  int* demands, /**< array of demands */
7148  int capacity, /**< cumulative capacity */
7149  int hmin, /**< left bound of time axis to be considered (including hmin) */
7150  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7151  SCIP_CONS* cons, /**< constraint which is propagated */
7152  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7153  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7154  int* nchgbds, /**< pointer to store the number of bound changes */
7155  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7156  )
7157 {
7158  /* check if a cutoff was already detected */
7159  if( (*cutoff) )
7160  return SCIP_OKAY;
7161 
7162  /* check if at least the basic overload checking should be preformed */
7163  if( !conshdlrdata->efcheck )
7164  return SCIP_OKAY;
7165 
7166  /* check for overload, which may result in a cutoff */
7167  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7168  cons, TRUE, initialized, explanation, nchgbds, cutoff) );
7169 
7170  /* check if a cutoff was detected */
7171  if( (*cutoff) )
7172  return SCIP_OKAY;
7173 
7174  /* check if bound should be infer */
7175  if( !conshdlrdata->efinfer )
7176  return SCIP_OKAY;
7177 
7178  /* check for overload, which may result in a cutoff */
7179  SCIP_CALL( checkOverloadViaThetaTree(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7180  cons, FALSE, initialized, explanation, nchgbds, cutoff) );
7181 
7182  return SCIP_OKAY;
7183 }
7184 
7185 /** checks if the constraint is redundant; that is the case if its capacity can never be exceeded; therefore we check
7186  * with respect to the lower and upper bounds of the integer start time variables the maximum capacity usage for all
7187  * event points
7188  */
7189 static
7191  SCIP* scip, /**< SCIP data structure */
7192  int nvars, /**< number of start time variables (activities) */
7193  SCIP_VAR** vars, /**< array of start time variables */
7194  int* durations, /**< array of durations */
7195  int* demands, /**< array of demands */
7196  int capacity, /**< cumulative capacity */
7197  int hmin, /**< left bound of time axis to be considered (including hmin) */
7198  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7199  SCIP_Bool* redundant /**< pointer to store whether this constraint is redundant */
7200  )
7201 {
7202  SCIP_VAR* var;
7203  int* starttimes; /* stores when each job is starting */
7204  int* endtimes; /* stores when each job ends */
7205  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
7206  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
7207 
7208  int lb;
7209  int ub;
7210  int freecapacity; /* remaining capacity */
7211  int curtime; /* point in time which we are just checking */
7212  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
7213  int njobs;
7214  int j;
7215 
7216  assert(scip != NULL);
7217  assert(redundant != NULL);
7218 
7219  (*redundant) = TRUE;
7220 
7221  /* if no activities are associated with this cumulative then this constraint is redundant */
7222  if( nvars == 0 )
7223  return SCIP_OKAY;
7224 
7225  assert(vars != NULL);
7226 
7227  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
7228  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
7229  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
7230  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
7231 
7232  njobs = 0;
7233 
7234  /* assign variables, start and endpoints to arrays */
7235  for( j = 0; j < nvars; ++j )
7236  {
7237  assert(durations[j] > 0);
7238  assert(demands[j] > 0);
7239 
7240  var = vars[j];
7241  assert(var != NULL);
7242 
7243  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7244  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7245 
7246  /* check if jobs runs completely outside of the effective time horizon */
7247  if( lb >= hmax || ub + durations[j] <= hmin )
7248  continue;
7249 
7250  starttimes[njobs] = MAX(lb, hmin);
7251  startindices[njobs] = j;
7252 
7253  endtimes[njobs] = MIN(ub + durations[j], hmax);
7254  endindices[njobs] = j;
7255  assert(starttimes[njobs] <= endtimes[njobs]);
7256  njobs++;
7257  }
7258 
7259  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues (and sort the indices in the same way) */
7260  SCIPsortIntInt(starttimes, startindices, njobs);
7261  SCIPsortIntInt(endtimes, endindices, njobs);
7262 
7263  endindex = 0;
7264  freecapacity = capacity;
7265 
7266  /* check each start point of a job whether the capacity is violated or not */
7267  for( j = 0; j < njobs; ++j )
7268  {
7269  curtime = starttimes[j];
7270 
7271  /* stop checking, if time point is above hmax */
7272  if( curtime >= hmax )
7273  break;
7274 
7275  /* subtract all capacity needed up to this point */
7276  freecapacity -= demands[startindices[j]];
7277  while( j+1 < njobs && starttimes[j+1] == curtime )
7278  {
7279  ++j;
7280  freecapacity -= demands[startindices[j]];
7281  }
7282 
7283  /* free all capacity usages of jobs the are no longer running */
7284  while( endtimes[endindex] <= curtime )
7285  {
7286  freecapacity += demands[endindices[endindex]];
7287  ++endindex;
7288  }
7289  assert(freecapacity <= capacity);
7290 
7291  /* check freecapacity to be smaller than zero */
7292  if( freecapacity < 0 && curtime >= hmin )
7293  {
7294  (*redundant) = FALSE;
7295  break;
7296  }
7297  } /*lint --e{850}*/
7298 
7299  /* free all buffer arrays */
7300  SCIPfreeBufferArray(scip, &endindices);
7301  SCIPfreeBufferArray(scip, &startindices);
7302  SCIPfreeBufferArray(scip, &endtimes);
7303  SCIPfreeBufferArray(scip, &starttimes);
7304 
7305  return SCIP_OKAY;
7306 }
7307 
7308 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
7309  * completion time
7310  */
7311 static
7313  SCIP* scip, /**< SCIP data structure */
7314  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7315  SCIP_PROFILE* profile, /**< resource profile */
7316  int nvars, /**< number of variables (jobs) */
7317  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
7318  int* durations, /**< array containing corresponding durations */
7319  int* demands, /**< array containing corresponding demands */
7320  int capacity, /**< cumulative capacity */
7321  int hmin, /**< left bound of time axis to be considered (including hmin) */
7322  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7323  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7324  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7325  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7326  )
7327 {
7328  int v;
7329 
7330  /* insert all cores */
7331  for( v = 0; v < nvars; ++v )
7332  {
7333  SCIP_VAR* var;
7334  SCIP_Bool infeasible;
7335  int duration;
7336  int demand;
7337  int begin;
7338  int end;
7339  int est;
7340  int lst;
7341  int pos;
7342 
7343  var = vars[v];
7344  assert(var != NULL);
7345  assert(SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(var)));
7346  assert(SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(var)));
7347 
7348  duration = durations[v];
7349  assert(duration > 0);
7350 
7351  demand = demands[v];
7352  assert(demand > 0);
7353 
7354  /* collect earliest and latest start time */
7355  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7356  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7357 
7358  /* check if the job runs completely outside of the effective horizon [hmin, hmax); if so skip it */
7359  if( lst + duration <= hmin || est >= hmax )
7360  continue;
7361 
7362  /* compute core interval w.r.t. effective time horizon */
7363  begin = MAX(hmin, lst);
7364  end = MIN(hmax, est + duration);
7365 
7366  /* check if a core exists */
7367  if( begin >= end )
7368  continue;
7369 
7370  SCIPdebugMsg(scip, "variable <%s>[%d,%d] (duration %d, demand %d): add core [%d,%d)\n",
7371  SCIPvarGetName(var), est, lst, duration, demand, begin, end);
7372 
7373  /* insert the core into core resource profile (complexity O(log n)) */
7374  SCIP_CALL( SCIPprofileInsertCore(profile, begin, end, demand, &pos, &infeasible) );
7375 
7376  /* in case the insertion of the core leads to an infeasibility; start the conflict analysis */
7377  if( infeasible )
7378  {
7379  assert(begin <= SCIPprofileGetTime(profile, pos));
7380  assert(end > SCIPprofileGetTime(profile, pos));
7381 
7382  /* use conflict analysis to analysis the core insertion which was infeasible */
7383  SCIP_CALL( analyseInfeasibelCoreInsertion(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
7384  var, duration, demand, SCIPprofileGetTime(profile, pos), conshdlrdata->usebdwidening, initialized, explanation) );
7385 
7386  if( explanation != NULL )
7387  explanation[v] = TRUE;
7388 
7389  (*cutoff) = TRUE;
7390 
7391  /* for the statistic we count the number of times a cutoff was detected due the time-time */
7392  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->ncutofftimetable++ );
7393 
7394  break;
7395  }
7396  }
7397 
7398  return SCIP_OKAY;
7399 }
7400 
7401 /** propagate the cumulative condition */
7402 static
7404  SCIP* scip, /**< SCIP data structure */
7405  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7406  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7407  int nvars, /**< number of start time variables (activities) */
7408  SCIP_VAR** vars, /**< array of start time variables */
7409  int* durations, /**< array of durations */
7410  int* demands, /**< array of demands */
7411  int capacity, /**< cumulative capacity */
7412  int hmin, /**< left bound of time axis to be considered (including hmin) */
7413  int hmax, /**< right bound of time axis to be considered (not including hmax) */
7414  SCIP_CONS* cons, /**< constraint which is propagated (needed to SCIPinferVar**Cons()) */
7415  int* nchgbds, /**< pointer to store the number of bound changes */
7416  SCIP_Bool* redundant, /**< pointer to store if the constraint is redundant */
7417  SCIP_Bool* initialized, /**< was conflict analysis initialized */
7418  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
7419  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7420  )
7421 {
7422  SCIP_PROFILE* profile;
7423 
7424  SCIP_RETCODE retcode = SCIP_OKAY;
7425 
7426  assert(nchgbds != NULL);
7427  assert(initialized != NULL);
7428  assert(cutoff != NULL);
7429  assert(!(*cutoff));
7430 
7431  /**@todo avoid always sorting the variable array */
7432 
7433  /* check if the constraint is redundant */
7434  SCIP_CALL( consCheckRedundancy(scip, nvars, vars, durations, demands, capacity, hmin, hmax, redundant) );
7435 
7436  if( *redundant )
7437  return SCIP_OKAY;
7438 
7439  /* create an empty resource profile for profiling the cores of the jobs */
7440  SCIP_CALL( SCIPprofileCreate(&profile, capacity) );
7441 
7442  /* create core profile (compulsory parts) */
7443  SCIP_CALL_TERMINATE( retcode, createCoreProfile(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax,
7444  initialized, explanation, cutoff), TERMINATE );
7445 
7446  /* propagate the job cores until nothing else can be detected */
7447  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
7448  {
7449  SCIP_CALL_TERMINATE( retcode, propagateTimetable(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7450  nchgbds, initialized, explanation, cutoff), TERMINATE );
7451  }
7452 
7453  /* run edge finding propagator */
7454  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
7455  {
7456  SCIP_CALL_TERMINATE( retcode, propagateEdgeFinding(scip, conshdlrdata, nvars, vars, durations, demands, capacity, hmin, hmax,
7457  cons, initialized, explanation, nchgbds, cutoff), TERMINATE );
7458  }
7459 
7460  /* run time-table edge-finding propagator */
7461  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
7462  {
7463  SCIP_CALL_TERMINATE( retcode, propagateTTEF(scip, conshdlrdata, profile, nvars, vars, durations, demands, capacity, hmin, hmax, cons,
7464  nchgbds, initialized, explanation, cutoff), TERMINATE );
7465  }
7466  /* free resource profile */
7467 TERMINATE:
7468  SCIPprofileFree(&profile);
7469 
7470  return retcode;
7471 }
7472 
7473 /** propagate the cumulative constraint */
7474 static
7476  SCIP* scip, /**< SCIP data structure */
7477  SCIP_CONS* cons, /**< constraint to propagate */
7478  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7479  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
7480  int* nchgbds, /**< pointer to store the number of bound changes */
7481  int* ndelconss, /**< pointer to store the number of deleted constraints */
7482  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
7483  )
7484 {
7485  SCIP_CONSDATA* consdata;
7486  SCIP_Bool initialized;
7487  SCIP_Bool redundant;
7488  int oldnchgbds;
7489 
7490  assert(scip != NULL);
7491  assert(cons != NULL);
7492 
7493  consdata = SCIPconsGetData(cons);
7494  assert(consdata != NULL);
7495 
7496  oldnchgbds = *nchgbds;
7497  initialized = FALSE;
7498  redundant = FALSE;
7499 
7500  if( SCIPconsIsDeleted(cons) )
7501  {
7502  assert(SCIPinProbing(scip));
7503  return SCIP_OKAY;
7504  }
7505 
7506  /* if the constraint marked to be propagated, do nothing */
7507  if( consdata->propagated && SCIPgetStage(scip) != SCIP_STAGE_PRESOLVING )
7508  return SCIP_OKAY;
7509 
7510  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
7511  consdata->nvars, consdata->vars, consdata->durations, consdata->demands, consdata->capacity,
7512  consdata->hmin, consdata->hmax, cons,
7513  nchgbds, &redundant, &initialized, NULL, cutoff) );
7514 
7515  if( redundant )
7516  {
7517  SCIPdebugMsg(scip, "%s deletes cumulative constraint <%s> since it is redundant\n",
7518  SCIPgetDepth(scip) == 0 ? "globally" : "locally", SCIPconsGetName(cons));
7519 
7520  if( !SCIPinProbing(scip) )
7521  {
7522  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7523  (*ndelconss)++;
7524  }
7525  }
7526  else
7527  {
7528  if( initialized )
7529  {
7530  /* run conflict analysis since it was initialized */
7531  assert(*cutoff == TRUE);
7532  SCIPdebugMsg(scip, "start conflict analysis\n");
7533  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
7534  }
7535 
7536  /* if successful, reset age of constraint */
7537  if( *cutoff || *nchgbds > oldnchgbds )
7538  {
7539  SCIP_CALL( SCIPresetConsAge(scip, cons) );
7540  }
7541  else
7542  {
7543  /* mark the constraint to be propagated */
7544  consdata->propagated = TRUE;
7545  }
7546  }
7547 
7548  return SCIP_OKAY;
7549 }
7550 
7551 /** it is dual feasible to remove the values {leftub+1, ..., rightlb-1} since SCIP current does not feature domain holes
7552  * we use the probing mode to check if one of the two branches is infeasible. If this is the case the dual redundant can
7553  * be realize as domain reduction. Otherwise we do nothing
7554  */
7555 static
7557  SCIP* scip, /**< SCIP data structure */
7558  SCIP_VAR** vars, /**< problem variables */
7559  int nvars, /**< number of problem variables */
7560  int probingpos, /**< variable number to apply probing on */
7561  SCIP_Real leftub, /**< upper bound of probing variable in left branch */
7562  SCIP_Real rightlb, /**< lower bound of probing variable in right branch */
7563  SCIP_Real* leftimpllbs, /**< lower bounds after applying implications and cliques in left branch, or NULL */
7564  SCIP_Real* leftimplubs, /**< upper bounds after applying implications and cliques in left branch, or NULL */
7565  SCIP_Real* leftproplbs, /**< lower bounds after applying domain propagation in left branch */
7566  SCIP_Real* leftpropubs, /**< upper bounds after applying domain propagation in left branch */
7567  SCIP_Real* rightimpllbs, /**< lower bounds after applying implications and cliques in right branch, or NULL */
7568  SCIP_Real* rightimplubs, /**< upper bounds after applying implications and cliques in right branch, or NULL */
7569  SCIP_Real* rightproplbs, /**< lower bounds after applying domain propagation in right branch */
7570  SCIP_Real* rightpropubs, /**< upper bounds after applying domain propagation in right branch */
7571  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7572  SCIP_Bool* success, /**< buffer to store whether a probing succeed to dual fix the variable */
7573  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7574  )
7575 {
7576  SCIP_VAR* var;
7577  SCIP_Bool tightened;
7578 
7579  assert(probingpos >= 0);
7580  assert(probingpos < nvars);
7581  assert(success != NULL);
7582  assert(cutoff != NULL);
7583 
7584  var = vars[probingpos];
7585  assert(var != NULL);
7586  assert(SCIPisGE(scip, leftub, SCIPvarGetLbLocal(var)));
7587  assert(SCIPisLE(scip, leftub, SCIPvarGetUbLocal(var)));
7588  assert(SCIPisGE(scip, rightlb, SCIPvarGetLbLocal(var)));
7589  assert(SCIPisLE(scip, rightlb, SCIPvarGetUbLocal(var)));
7590 
7591  (*success) = FALSE;
7592 
7593  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
7594  return SCIP_OKAY;
7595 
7596  /* apply probing for the earliest start time (lower bound) of the variable (x <= est) */
7597  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_UPPER, leftub, -1,
7598  leftimpllbs, leftimplubs, leftproplbs, leftpropubs, cutoff) );
7599 
7600  if( (*cutoff) )
7601  {
7602  /* note that cutoff may occur if presolving has not been executed fully */
7603  SCIP_CALL( SCIPtightenVarLb(scip, var, rightlb, TRUE, cutoff, &tightened) );
7604 
7605  if( tightened )
7606  {
7607  (*success) =TRUE;
7608  (*nfixedvars)++;
7609  }
7610 
7611  return SCIP_OKAY;
7612  }
7613 
7614  /* note that probing can change the upper bound and thus the right branch may have been detected infeasible if
7615  * presolving has not been executed fully
7616  */
7617  if( SCIPisGT(scip, rightlb, SCIPvarGetUbLocal(var)) )
7618  {
7619  /* note that cutoff may occur if presolving has not been executed fully */
7620  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7621 
7622  if( tightened )
7623  {
7624  (*success) = TRUE;
7625  (*nfixedvars)++;
7626  }
7627 
7628  return SCIP_OKAY;
7629  }
7630 
7631  /* apply probing for the alternative lower bound of the variable (x <= alternativeubs[v]) */
7632  SCIP_CALL( SCIPapplyProbingVar(scip, vars, nvars, probingpos, SCIP_BOUNDTYPE_LOWER, rightlb, -1,
7633  rightimpllbs, rightimplubs, rightproplbs, rightpropubs, cutoff) );
7634 
7635  if( (*cutoff) )
7636  {
7637  /* note that cutoff may occur if presolving has not been executed fully */
7638  SCIP_CALL( SCIPtightenVarUb(scip, var, leftub, TRUE, cutoff, &tightened) );
7639 
7640  if( tightened )
7641  {
7642  (*success) =TRUE;
7643  (*nfixedvars)++;
7644  }
7645 
7646  return SCIP_OKAY;
7647  }
7648 
7649  return SCIP_OKAY;
7650 }
7651 
7652 /** is it possible, to round variable down w.r.t. objective function */
7653 static
7655  SCIP* scip, /**< SCIP data structure */
7656  SCIP_VAR* var, /**< problem variable */
7657  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7658  )
7659 {
7660  SCIP_Real objval;
7661  int scalar;
7662 
7663  assert(roundable != NULL);
7664 
7665  *roundable = TRUE;
7666 
7667  /* a fixed variable can be definition always be safely rounded */
7669  return SCIP_OKAY;
7670 
7671  /* in case the variable is not active we need to check the object coefficient of the active variable */
7672  if( !SCIPvarIsActive(var) )
7673  {
7674  SCIP_VAR* actvar;
7675  int constant;
7676 
7677  actvar = var;
7678 
7679  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7680  assert(scalar != 0);
7681 
7682  objval = scalar * SCIPvarGetObj(actvar);
7683  } /*lint !e438*/
7684  else
7685  {
7686  scalar = 1;
7687  objval = SCIPvarGetObj(var);
7688  }
7689 
7690  /* rounding the integer variable down is only a valid dual reduction if the object coefficient is zero or positive
7691  * (the transformed problem is always a minimization problem)
7692  *
7693  * @note that we need to check this condition w.r.t. active variable space
7694  */
7695  if( (scalar > 0 && SCIPisNegative(scip, objval)) || (scalar < 0 && SCIPisPositive(scip, objval)) )
7696  *roundable = FALSE;
7697 
7698  return SCIP_OKAY;
7699 }
7700 
7701 /** is it possible, to round variable up w.r.t. objective function */
7702 static
7704  SCIP* scip, /**< SCIP data structure */
7705  SCIP_VAR* var, /**< problem variable */
7706  SCIP_Bool* roundable /**< pointer to store if the variable can be rounded down */
7707  )
7708 {
7709  SCIP_Real objval;
7710  int scalar;
7711 
7712  assert(roundable != NULL);
7713 
7714  *roundable = TRUE;
7715 
7716  /* a fixed variable can be definition always be safely rounded */
7718  return SCIP_OKAY;
7719 
7720  /* in case the variable is not active we need to check the object coefficient of the active variable */
7721  if( !SCIPvarIsActive(var) )
7722  {
7723  SCIP_VAR* actvar;
7724  int constant;
7725 
7726  actvar = var;
7727 
7728  SCIP_CALL( getActiveVar(scip, &actvar, &scalar, &constant) );
7729  assert(scalar != 0);
7730 
7731  objval = scalar * SCIPvarGetObj(actvar);
7732  } /*lint !e438*/
7733  else
7734  {
7735  scalar = 1;
7736  objval = SCIPvarGetObj(var);
7737  }
7738 
7739  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
7740  * (the transformed problem is always a minimization problem)
7741  *
7742  * @note that we need to check this condition w.r.t. active variable space
7743  */
7744  if( (scalar > 0 && SCIPisPositive(scip, objval)) || (scalar < 0 && SCIPisNegative(scip, objval)) )
7745  *roundable = FALSE;
7746 
7747  return SCIP_OKAY;
7748 }
7749 
7750 /** For each variable we compute an alternative lower and upper bounds. That is, if the variable is not fixed to its
7751  * lower or upper bound the next reasonable lower or upper bound would be this alternative bound (implying that certain
7752  * values are not of interest). An alternative bound for a particular is only valied if the cumulative constarints are
7753  * the only one locking this variable in the corresponding direction.
7754  */
7755 static
7757  SCIP* scip, /**< SCIP data structure */
7758  SCIP_CONS** conss, /**< array of cumulative constraint constraints */
7759  int nconss, /**< number of cumulative constraints */
7760  SCIP_Bool local, /**< use local bounds effective horizon? */
7761  int* alternativelbs, /**< alternative lower bounds */
7762  int* alternativeubs, /**< alternative lower bounds */
7763  int* downlocks, /**< number of constraints with down lock participating by the computation */
7764  int* uplocks /**< number of constraints with up lock participating by the computation */
7765  )
7766 {
7767  int nvars;
7768  int c;
7769  int v;
7770 
7771  for( c = 0; c < nconss; ++c )
7772  {
7773  SCIP_CONSDATA* consdata;
7774  SCIP_CONS* cons;
7775  SCIP_VAR* var;
7776  int hmin;
7777  int hmax;
7778 
7779  cons = conss[c];
7780  assert(cons != NULL);
7781 
7782  /* ignore constraints which are already deletet and those which are not check constraints */
7783  if( SCIPconsIsDeleted(cons) || !SCIPconsIsChecked(cons) )
7784  continue;
7785 
7786  consdata = SCIPconsGetData(cons);
7787  assert(consdata != NULL);
7788  assert(consdata->nvars > 1);
7789 
7790  /* compute the hmin and hmax */
7791  if( local )
7792  {
7793  SCIP_PROFILE* profile;
7794  SCIP_RETCODE retcode;
7795 
7796  /* create empty resource profile with infinity resource capacity */
7797  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
7798 
7799  /* create worst case resource profile */
7800  retcode = SCIPcreateWorstCaseProfile(scip, profile, consdata->nvars, consdata->vars, consdata->durations, consdata->demands);
7801 
7802  hmin = SCIPcomputeHmin(scip, profile, consdata->capacity);
7803  hmax = SCIPcomputeHmax(scip, profile, consdata->capacity);
7804 
7805  /* free worst case profile */
7806  SCIPprofileFree(&profile);
7807 
7808  if( retcode != SCIP_OKAY )
7809  return retcode;
7810  }
7811  else
7812  {
7813  hmin = consdata->hmin;
7814  hmax = consdata->hmax;
7815  }
7816 
7817  consdata = SCIPconsGetData(cons);
7818  assert(consdata != NULL);
7819 
7820  nvars = consdata->nvars;
7821 
7822  for( v = 0; v < nvars; ++v )
7823  {
7824  int scalar;
7825  int constant;
7826  int idx;
7827 
7828  var = consdata->vars[v];
7829  assert(var != NULL);
7830 
7831  /* multi-aggregated variables should appear here since we mark the variables to be not mutlt-aggregated */
7832  assert(SCIPvarGetStatus(var) != SCIP_VARSTATUS_MULTAGGR);
7833 
7834  /* ignore variable locally fixed variables */
7835  if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
7836  continue;
7837 
7838  SCIP_CALL( getActiveVar(scip, &var, &scalar, &constant) );
7839  idx = SCIPvarGetProbindex(var);
7840  assert(idx >= 0);
7841 
7842  /* first check lower bound fixing */
7843  if( consdata->downlocks[v] )
7844  {
7845  int ect;
7846  int est;
7847 
7848  /* the variable has a down locked */
7849  est = scalar * SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var)) + constant;
7850  ect = est + consdata->durations[v];
7851 
7852  if( ect <= hmin || hmin >= hmax )
7853  downlocks[idx]++;
7854  else if( est < hmin && alternativelbs[idx] >= (hmin + 1 - constant) / scalar )
7855  {
7856  alternativelbs[idx] = (hmin + 1 - constant) / scalar;
7857  downlocks[idx]++;
7858  }
7859  }
7860 
7861  /* second check upper bound fixing */
7862  if( consdata->uplocks[v] )
7863  {
7864  int duration;
7865  int lct;
7866  int lst;
7867 
7868  duration = consdata->durations[v];
7869 
7870  /* the variable has a up lock locked */
7871  lst = scalar * SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + constant;
7872  lct = lst + duration;
7873 
7874  if( lst >= hmax || hmin >= hmax )
7875  uplocks[idx]++;
7876  else if( lct > hmax && alternativeubs[idx] <= ((hmax - 1 - constant) / scalar) - duration )
7877  {
7878  alternativeubs[idx] = ((hmax - 1 - constant) / scalar) - duration;
7879  uplocks[idx]++;
7880  }
7881  }
7882  }
7883  }
7884 
7885  return SCIP_OKAY;
7886 }
7887 
7888 /** apply all fixings which are given by the alternative bounds */
7889 static
7891  SCIP* scip, /**< SCIP data structure */
7892  SCIP_VAR** vars, /**< array of active variables */
7893  int nvars, /**< number of active variables */
7894  int* alternativelbs, /**< alternative lower bounds */
7895  int* alternativeubs, /**< alternative lower bounds */
7896  int* downlocks, /**< number of constraints with down lock participating by the computation */
7897  int* uplocks, /**< number of constraints with up lock participating by the computation */
7898  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
7899  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
7900  )
7901 {
7902  SCIP_Real* downimpllbs;
7903  SCIP_Real* downimplubs;
7904  SCIP_Real* downproplbs;
7905  SCIP_Real* downpropubs;
7906  SCIP_Real* upimpllbs;
7907  SCIP_Real* upimplubs;
7908  SCIP_Real* upproplbs;
7909  SCIP_Real* uppropubs;
7910  int v;
7911 
7912  /* get temporary memory for storing probing results */
7913  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
7914  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
7915  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
7916  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
7917  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
7918  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
7919  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
7920  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
7921 
7922  for( v = 0; v < nvars; ++v )
7923  {
7924  SCIP_VAR* var;
7925  SCIP_Bool infeasible;
7926  SCIP_Bool fixed;
7927  SCIP_Bool roundable;
7928  int ub;
7929  int lb;
7930 
7931  var = vars[v];
7932  assert(var != NULL);
7933 
7934  /* ignore variables for which no alternative bounds have been computed */
7935  if( alternativelbs[v] == INT_MAX && alternativeubs[v] == INT_MIN )
7936  continue;
7937 
7938  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7939  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7940 
7941  /* ignore fixed variables */
7942  if( ub - lb <= 0 )
7943  continue;
7944 
7945  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == downlocks[v] )
7946  {
7947  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
7948 
7949  if( roundable )
7950  {
7951  if( alternativelbs[v] > ub )
7952  {
7953  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
7954  assert(!infeasible);
7955  assert(fixed);
7956 
7957  (*nfixedvars)++;
7958 
7959  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
7960  * constraints
7961  */
7962  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7963  }
7964  else
7965  {
7966  SCIP_Bool success;
7967 
7968  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
7969  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
7970  * infeasible we can apply the dual reduction; otherwise we do nothing
7971  */
7972  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) lb, (SCIP_Real) alternativelbs[v],
7973  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
7974  nfixedvars, &success, cutoff) );
7975 
7976  if( success )
7977  {
7978  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
7979  }
7980  }
7981  }
7982  }
7983 
7984  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
7985  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var));
7986 
7987  /* ignore fixed variables */
7988  if( ub - lb <= 0 )
7989  continue;
7990 
7991  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == uplocks[v] )
7992  {
7993  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
7994 
7995  if( roundable )
7996  {
7997  if( alternativeubs[v] < lb )
7998  {
7999  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
8000  assert(!infeasible);
8001  assert(fixed);
8002 
8003  (*nfixedvars)++;
8004 
8005  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
8006  * constraints
8007  */
8008  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
8009  }
8010  else
8011  {
8012  SCIP_Bool success;
8013 
8014  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
8015  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
8016  * infeasible we can apply the dual reduction; otherwise we do nothing
8017  */
8018  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeubs[v], (SCIP_Real) ub,
8019  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
8020  nfixedvars, &success, cutoff) );
8021 
8022  if( success )
8023  {
8024  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nallconsdualfixs++ );
8025  }
8026  }
8027  }
8028  }
8029  }
8030 
8031  /* free temporary memory */
8032  SCIPfreeBufferArray(scip, &uppropubs);
8033  SCIPfreeBufferArray(scip, &upproplbs);
8034  SCIPfreeBufferArray(scip, &upimplubs);
8035  SCIPfreeBufferArray(scip, &upimpllbs);
8036  SCIPfreeBufferArray(scip, &downpropubs);
8037  SCIPfreeBufferArray(scip, &downproplbs);
8038  SCIPfreeBufferArray(scip, &downimplubs);
8039  SCIPfreeBufferArray(scip, &downimpllbs);
8040 
8041  return SCIP_OKAY;
8042 }
8043 
8044 /** propagate all constraints together */
8045 static
8047  SCIP* scip, /**< SCIP data structure */
8048  SCIP_CONS** conss, /**< all cumulative constraint */
8049  int nconss, /**< number of cumulative constraints */
8050  SCIP_Bool local, /**< use local bounds effective horizon? */
8051  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
8052  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff is detected */
8053  SCIP_Bool* branched /**< pointer to store if a branching was applied, or NULL to avoid branching */
8054  )
8055 { /*lint --e{715}*/
8056  SCIP_VAR** vars;
8057  int* downlocks;
8058  int* uplocks;
8059  int* alternativelbs;
8060  int* alternativeubs;
8061  int oldnfixedvars;
8062  int nvars;
8063  int v;
8064 
8065  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
8066  return SCIP_OKAY;
8067 
8068  nvars = SCIPgetNVars(scip);
8069  oldnfixedvars = *nfixedvars;
8070 
8071  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
8072  SCIP_CALL( SCIPallocBufferArray(scip, &downlocks, nvars) );
8073  SCIP_CALL( SCIPallocBufferArray(scip, &uplocks, nvars) );
8074  SCIP_CALL( SCIPallocBufferArray(scip, &alternativelbs, nvars) );
8075  SCIP_CALL( SCIPallocBufferArray(scip, &alternativeubs, nvars) );
8076 
8077  /* initialize arrays */
8078  for( v = 0; v < nvars; ++v )
8079  {
8080  downlocks[v] = 0;
8081  uplocks[v] = 0;
8082  alternativelbs[v] = INT_MAX;
8083  alternativeubs[v] = INT_MIN;
8084  }
8085 
8086  /* compute alternative bounds */
8087  SCIP_CALL( computeAlternativeBounds(scip, conss, nconss, local, alternativelbs, alternativeubs, downlocks, uplocks) );
8088 
8089  /* apply fixing which result of the alternative bounds directly */
8090  SCIP_CALL( applyAlternativeBoundsFixing(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks,
8091  nfixedvars, cutoff) );
8092 
8093  if( !(*cutoff) && oldnfixedvars == *nfixedvars && branched != NULL )
8094  {
8095  SCIP_CALL( applyAlternativeBoundsBranching(scip, vars, nvars, alternativelbs, alternativeubs, downlocks, uplocks, branched) );
8096  }
8097 
8098  /* free all buffers */
8099  SCIPfreeBufferArray(scip, &alternativeubs);
8100  SCIPfreeBufferArray(scip, &alternativelbs);
8101  SCIPfreeBufferArray(scip, &uplocks);
8102  SCIPfreeBufferArray(scip, &downlocks);
8103  SCIPfreeBufferArray(scip, &vars);
8104 
8105  return SCIP_OKAY;
8106 }
8107 
8108 /**@} */
8109 
8110 /**@name Linear relaxations
8111  *
8112  * @{
8113  */
8114 
8115 /** creates covering cuts for jobs violating resource constraints */
8116 static
8118  SCIP* scip, /**< SCIP data structure */
8119  SCIP_CONS* cons, /**< constraint to be checked */
8120  int* startvalues, /**< upper bounds on finishing time per job for activities from 0,..., nactivities -1 */
8121  int time /**< at this point in time covering constraints are valid */
8122  )
8123 {
8124  SCIP_CONSDATA* consdata;
8125  SCIP_ROW* row;
8126  int* flexibleids;
8127  int* demands;
8128 
8129  char rowname[SCIP_MAXSTRLEN];
8130 
8131  int remainingcap;
8132  int smallcoversize; /* size of a small cover */
8133  int bigcoversize; /* size of a big cover */
8134  int nvars;
8135 
8136  int nflexible;
8137  int sumdemand; /* demand of all jobs up to a certain index */
8138  int j;
8139 
8140  assert(cons != NULL);
8141 
8142  /* get constraint data structure */
8143  consdata = SCIPconsGetData(cons);
8144  assert(consdata != NULL );
8145 
8146  nvars = consdata->nvars;
8147 
8148  /* sort jobs according to demands */
8149  SCIP_CALL( SCIPallocBufferArray(scip, &demands, nvars) );
8150  SCIP_CALL( SCIPallocBufferArray(scip, &flexibleids, nvars) );
8151 
8152  nflexible = 0;
8153  remainingcap = consdata->capacity;
8154 
8155  /* get all jobs intersecting point 'time' with their bounds */
8156  for( j = 0; j < nvars; ++j )
8157  {
8158  int ub;
8159 
8160  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j]));
8161 
8162  /* only add jobs to array if they intersect with point 'time' */
8163  if( startvalues[j] <= time && ub + consdata->durations[j] > time )
8164  {
8165  /* if job is fixed, capacity has to be decreased */
8166  if( startvalues[j] == ub )
8167  {
8168  remainingcap -= consdata->demands[j];
8169  }
8170  else
8171  {
8172  demands[nflexible] = consdata->demands[j];
8173  flexibleids[nflexible] = j;
8174  ++nflexible;
8175  }
8176  }
8177  }
8178  assert(remainingcap >= 0);
8179 
8180  /* sort demands and job ids */
8181  SCIPsortIntInt(demands, flexibleids, nflexible);
8182 
8183  /*
8184  * version 1:
8185  * D_j := sum_i=0,...,j d_i, finde j maximal, so dass D_j <= remainingcap
8186  * erzeuge cover constraint
8187  *
8188  */
8189 
8190  /* find maximum number of jobs that can run in parallel (-->coversize = j) */
8191  sumdemand = 0;
8192  j = 0;
8193 
8194  while( j < nflexible && sumdemand <= remainingcap )
8195  {
8196  sumdemand += demands[j];
8197  j++;
8198  }
8199 
8200  /* j jobs form a conflict, set coversize to 'j - 1' */
8201  bigcoversize = j-1;
8202  assert(sumdemand > remainingcap);
8203  assert(bigcoversize < nflexible);
8204 
8205  /* - create a row for all jobs and their binary variables.
8206  * - at most coversize many binary variables of jobs can be set to one
8207  */
8208 
8209  /* construct row name */
8210  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coverbig_%d", time);
8211  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)bigcoversize,
8212  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8213  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8214 
8215  for( j = 0; j < nflexible; ++j )
8216  {
8217  SCIP_VAR** binvars;
8218  SCIP_Real* vals;
8219  int nbinvars;
8220  int idx;
8221  int start;
8222  int end;
8223  int lb;
8224  int ub;
8225  int b;
8226 
8227  idx = flexibleids[j];
8228 
8229  /* get and add binvars into var array */
8230  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8231  assert(nbinvars != 0);
8232 
8233  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8234  assert(vals != NULL);
8235 
8236  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8237  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8238 
8239  /* compute start and finishing time */
8240  start = time - consdata->durations[idx] + 1;
8241  end = MIN(time, ub);
8242 
8243  /* add all neccessary binary variables */
8244  for( b = 0; b < nbinvars; ++b )
8245  {
8246  if( vals[b] < start || vals[b] < lb )
8247  continue;
8248 
8249  if( vals[b] > end )
8250  break;
8251 
8252  assert(binvars[b] != NULL);
8253  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8254  }
8255  }
8256 
8257  /* insert and release row */
8258  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8259 
8260  if( consdata->bcoverrowssize == 0 )
8261  {
8262  consdata->bcoverrowssize = 10;
8263  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->bcoverrowssize) );
8264  }
8265  if( consdata->nbcoverrows == consdata->bcoverrowssize )
8266  {
8267  consdata->bcoverrowssize *= 2;
8268  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bcoverrows, consdata->nbcoverrows, consdata->bcoverrowssize) );
8269  }
8270 
8271  consdata->bcoverrows[consdata->nbcoverrows] = row;
8272  consdata->nbcoverrows++;
8273 
8274  /*
8275  * version 2:
8276  * D_j := sum_i=j,...,0 d_i, finde j minimal, so dass D_j <= remainingcap
8277  * erzeuge cover constraint und fuege alle jobs i hinzu, mit d_i = d_largest
8278  */
8279  /* find maximum number of jobs that can run in parallel (= coversize -1) */
8280  sumdemand = 0;
8281  j = nflexible -1;
8282  while( sumdemand <= remainingcap )
8283  {
8284  assert(j >= 0);
8285  sumdemand += demands[j];
8286  j--;
8287  }
8288 
8289  smallcoversize = nflexible - (j + 1) - 1;
8290  while( j > 0 && demands[j] == demands[nflexible-1] )
8291  --j;
8292 
8293  assert(smallcoversize < nflexible);
8294 
8295  if( smallcoversize != 1 || smallcoversize != nflexible - (j + 1) - 1 )
8296  {
8297  /* construct row name */
8298  (void)SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "capacity_coversmall_%d", time);
8299  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, rowname, -SCIPinfinity(scip), (SCIP_Real)smallcoversize,
8300  SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), TRUE) );
8301  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8302 
8303  /* filter binary variables for each unfixed job */
8304  for( j = j + 1; j < nflexible; ++j )
8305  {
8306  SCIP_VAR** binvars;
8307  SCIP_Real* vals;
8308  int nbinvars;
8309  int idx;
8310  int start;
8311  int end;
8312  int lb;
8313  int ub;
8314  int b;
8315 
8316  idx = flexibleids[j];
8317 
8318  /* get and add binvars into var array */
8319  SCIP_CALL( SCIPgetBinvarsLinking(scip, consdata->linkingconss[idx], &binvars, &nbinvars) );
8320  assert(nbinvars != 0);
8321 
8322  vals = SCIPgetValsLinking(scip, consdata->linkingconss[idx]);
8323  assert(vals != NULL);
8324 
8325  lb = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[idx]));
8326  ub = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[idx]));
8327 
8328  /* compute start and finishing time */
8329  start = time - consdata->durations[idx] + 1;
8330  end = MIN(time, ub);
8331 
8332  /* add all neccessary binary variables */
8333  for( b = 0; b < nbinvars; ++b )
8334  {
8335  if( vals[b] < start || vals[b] < lb )
8336  continue;
8337 
8338  if( vals[b] > end )
8339  break;
8340 
8341  assert(binvars[b] != NULL);
8342  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], 1.0) );
8343  }
8344  }
8345 
8346  /* insert and release row */
8347  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8348  if( consdata->scoverrowssize == 0 )
8349  {
8350  consdata->scoverrowssize = 10;
8351  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->scoverrowssize) );
8352  }
8353  if( consdata->nscoverrows == consdata->scoverrowssize )
8354  {
8355  consdata->scoverrowssize *= 2;
8356  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->scoverrows, consdata->nscoverrows, consdata->scoverrowssize) );
8357  }
8358 
8359  consdata->scoverrows[consdata->nscoverrows] = row;
8360  consdata->nscoverrows++;
8361  }
8362 
8363  /* free buffer arrays */
8364  SCIPfreeBufferArray(scip, &flexibleids);
8365  SCIPfreeBufferArray(scip, &demands);
8366 
8367  return SCIP_OKAY;
8368 }
8369 
8370 /** method to construct cover cuts for all points in time */
8371 static
8373  SCIP* scip, /**< SCIP data structure */
8374  SCIP_CONS* cons /**< constraint to be separated */
8375  )
8376 {
8377  SCIP_CONSDATA* consdata;
8378 
8379  int* startvalues; /* stores when each job is starting */
8380  int* endvalues; /* stores when each job ends */
8381  int* startvaluessorted; /* stores when each job is starting */
8382  int* endvaluessorted; /* stores when each job ends */
8383  int* startindices; /* we sort the startvalues, so we need to know wich index of a job it corresponds to */
8384  int* endindices; /* we sort the endvalues, so we need to know wich index of a job it corresponds to */
8385 
8386  int nvars; /* number of jobs for this constraint */
8387  int freecapacity; /* remaining capacity */
8388  int curtime; /* point in time which we are just checking */
8389  int endidx; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8390 
8391  int hmin;
8392  int hmax;
8393 
8394  int j;
8395  int t;
8396 
8397  assert(scip != NULL);
8398  assert(cons != NULL);
8399 
8400  consdata = SCIPconsGetData(cons);
8401  assert(consdata != NULL);
8402 
8403  /* if no activities are associated with this resource then this constraint is redundant */
8404  if( consdata->vars == NULL )
8405  return SCIP_OKAY;
8406 
8407  nvars = consdata->nvars;
8408  hmin = consdata->hmin;
8409  hmax = consdata->hmax;
8410 
8411  SCIP_CALL( SCIPallocBufferArray(scip, &startvalues, nvars) );
8412  SCIP_CALL( SCIPallocBufferArray(scip, &endvalues, nvars) );
8413  SCIP_CALL( SCIPallocBufferArray(scip, &startvaluessorted, nvars) );
8414  SCIP_CALL( SCIPallocBufferArray(scip, &endvaluessorted, nvars) );
8415  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8416  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8417 
8418  /* assign start and endpoints to arrays */
8419  for ( j = 0; j < nvars; ++j )
8420  {
8421  startvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
8422  startvaluessorted[j] = startvalues[j];
8423 
8424  endvalues[j] = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
8425  endvaluessorted[j] = endvalues[j];
8426 
8427  startindices[j] = j;
8428  endindices[j] = j;
8429  }
8430 
8431  /* sort the arrays not-decreasing according to startsolvalues and endsolvalues
8432  * (and sort the indices in the same way) */
8433  SCIPsortIntInt(startvaluessorted, startindices, nvars);
8434  SCIPsortIntInt(endvaluessorted, endindices, nvars);
8435 
8436  endidx = 0;
8437  freecapacity = consdata->capacity;
8438 
8439  /* check each startpoint of a job whether the capacity is kept or not */
8440  for( j = 0; j < nvars; ++j )
8441  {
8442  curtime = startvaluessorted[j];
8443  if( curtime >= hmax )
8444  break;
8445 
8446  /* subtract all capacity needed up to this point */
8447  freecapacity -= consdata->demands[startindices[j]];
8448 
8449  while( j+1 < nvars && startvaluessorted[j+1] == curtime )
8450  {
8451  ++j;
8452  freecapacity -= consdata->demands[startindices[j]];
8453  }
8454 
8455  /* free all capacity usages of jobs the are no longer running */
8456  while( endidx < nvars && curtime >= endvaluessorted[endidx] )
8457  {
8458  freecapacity += consdata->demands[endindices[endidx]];
8459  ++endidx;
8460  }
8461 
8462  assert(freecapacity <= consdata->capacity);
8463  assert(endidx <= nvars);
8464 
8465  /* --> endindex - points to the next job which will finish
8466  * j - points to the last job that has been released
8467  */
8468 
8469  /* check freecapacity to be smaller than zero
8470  * then we will add cover constraints to the MIP
8471  */
8472  if( freecapacity < 0 && curtime >= hmin )
8473  {
8474  int nextprofilechange;
8475 
8476  /* we can create covering constraints for each pint in time in interval [curtime; nextprofilechange[ */
8477  if( j < nvars-1 )
8478  nextprofilechange = MIN( startvaluessorted[j+1], endvaluessorted[endidx] );
8479  else
8480  nextprofilechange = endvaluessorted[endidx];
8481 
8482  nextprofilechange = MIN(nextprofilechange, hmax);
8483 
8484  for( t = curtime; t < nextprofilechange; ++t )
8485  {
8486  SCIPdebugMsg(scip, "add cover constraint for time %d\n", curtime);
8487 
8488  /* create covering constraint */
8489  SCIP_CALL( createCoverCutsTimepoint(scip, cons, startvalues, t) );
8490  }
8491  } /* end if freecapacity > 0 */
8492  } /*lint --e{850}*/
8493 
8494  consdata->covercuts = TRUE;
8495 
8496  /* free all buffer arrays */
8497  SCIPfreeBufferArray(scip, &endindices);
8498  SCIPfreeBufferArray(scip, &startindices);
8499  SCIPfreeBufferArray(scip, &endvaluessorted);
8500  SCIPfreeBufferArray(scip, &startvaluessorted);
8501  SCIPfreeBufferArray(scip, &endvalues);
8502  SCIPfreeBufferArray(scip, &startvalues);
8503 
8504  return SCIP_OKAY;
8505 }
8506 
8507 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
8508  * constraint
8509  */
8510 static
8512  SCIP* scip, /**< SCIP data structure */
8513  SCIP_CONS* cons, /**< constraint to be checked */
8514  int* startindices, /**< permutation with rspect to the start times */
8515  int curtime, /**< current point in time */
8516  int nstarted, /**< number of jobs that start before the curtime or at curtime */
8517  int nfinished, /**< number of jobs that finished before curtime or at curtime */
8518  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8519  )
8520 {
8521  SCIP_CONSDATA* consdata;
8522  SCIP_VAR** binvars;
8523  int* coefs;
8524  int nbinvars;
8525  char name[SCIP_MAXSTRLEN];
8526  int capacity;
8527  int b;
8528 
8529  assert(nstarted > nfinished);
8530 
8531  consdata = SCIPconsGetData(cons);
8532  assert(consdata != NULL);
8533  assert(consdata->nvars > 0);
8534 
8535  capacity = consdata->capacity;
8536  assert(capacity > 0);
8537 
8538  nbinvars = 0;
8539  SCIP_CALL( collectBinaryVars(scip, consdata, &binvars, &coefs, &nbinvars, startindices, curtime, nstarted, nfinished) );
8540 
8541  /* construct row name */
8542  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d[%d]", SCIPconsGetName(cons), nstarted-1, curtime);
8543 
8544  if( cutsasconss )
8545  {
8546  SCIP_CONS* lincons;
8547 
8548  /* create knapsack constraint for the given time point */
8549  SCIP_CALL( SCIPcreateConsKnapsack(scip, &lincons, name, 0, NULL, NULL, (SCIP_Longint)(capacity),
8550  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE) );
8551 
8552  for( b = 0; b < nbinvars; ++b )
8553  {
8554  SCIP_CALL( SCIPaddCoefKnapsack(scip, lincons, binvars[b], (SCIP_Longint)coefs[b]) );
8555  }
8556 
8557  /* add and release the new constraint */
8558  SCIP_CALL( SCIPaddCons(scip, lincons) );
8559  SCIP_CALL( SCIPreleaseCons(scip, &lincons) );
8560  }
8561  else
8562  {
8563  SCIP_ROW* row;
8564 
8565  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real)capacity, FALSE, FALSE, SCIPconsIsRemovable(cons)) );
8566  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
8567 
8568  for( b = 0; b < nbinvars; ++b )
8569  {
8570  SCIP_CALL( SCIPaddVarToRow(scip, row, binvars[b], (SCIP_Real)coefs[b]) );
8571  }
8572 
8573  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
8574  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
8575 
8576  if( consdata->demandrowssize == 0 )
8577  {
8578  consdata->demandrowssize = 10;
8579  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->demandrows, consdata->demandrowssize) );
8580  }
8581  if( consdata->ndemandrows == consdata->demandrowssize )
8582  {
8583  consdata->demandrowssize *= 2;
8584  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->demandrows, consdata->ndemandrows, consdata->demandrowssize) );
8585  }
8586 
8587  consdata->demandrows[consdata->ndemandrows] = row;
8588  consdata->ndemandrows++;
8589  }
8590 
8591  SCIPfreeBufferArrayNull(scip, &binvars);
8592  SCIPfreeBufferArrayNull(scip, &coefs);
8593 
8594  return SCIP_OKAY;
8595 }
8596 
8597 /** this method checks how many cumulatives can run at most at one time if this is greater than the capacity it creates
8598  * row
8599  */
8600 static
8602  SCIP* scip, /**< SCIP data structure */
8603  SCIP_CONS* cons, /**< constraint to be checked */
8604  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8605  )
8606 {
8607  SCIP_CONSDATA* consdata;
8608 
8609  int* starttimes; /* stores when each job is starting */
8610  int* endtimes; /* stores when each job ends */
8611  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
8612  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
8613 
8614  int nvars; /* number of activities for this constraint */
8615  int freecapacity; /* remaining capacity */
8616  int curtime; /* point in time which we are just checking */
8617  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
8618 
8619  int hmin;
8620  int hmax;
8621 
8622  int j;
8623 
8624  assert(scip != NULL);
8625  assert(cons != NULL);
8626 
8627  consdata = SCIPconsGetData(cons);
8628  assert(consdata != NULL);
8629 
8630  nvars = consdata->nvars;
8631 
8632  /* if no activities are associated with this cumulative then this constraint is redundant */
8633  if( nvars == 0 )
8634  return SCIP_OKAY;
8635 
8636  assert(consdata->vars != NULL);
8637 
8638  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
8639  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
8640  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
8641  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
8642 
8643  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
8644  SCIPconsGetName(cons), nvars);
8645 
8646  /* create event point arrays */
8647  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
8648  starttimes, endtimes, startindices, endindices, FALSE);
8649 
8650  endindex = 0;
8651  freecapacity = consdata->capacity;
8652  hmin = consdata->hmin;
8653  hmax = consdata->hmax;
8654 
8655  /* check each startpoint of a job whether the capacity is kept or not */
8656  for( j = 0; j < nvars; ++j )
8657  {
8658  curtime = starttimes[j];
8659  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
8660 
8661  if( curtime >= hmax )
8662  break;
8663 
8664  /* remove the capacity requirments for all job which start at the curtime */
8665  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
8666 
8667  /* add the capacity requirments for all job which end at the curtime */
8668  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
8669 
8670  assert(freecapacity <= consdata->capacity);
8671  assert(endindex <= nvars);
8672 
8673  /* endindex - points to the next job which will finish */
8674  /* j - points to the last job that has been released */
8675 
8676  /* if free capacity is smaller than zero, then add rows to the LP */
8677  if( freecapacity < 0 && curtime >= hmin )
8678  {
8679  int nextstarttime;
8680  int t;
8681 
8682  /* step forward until next job is released and see whether capacity constraint is met or not */
8683  if( j < nvars-1 )
8684  nextstarttime = starttimes[j+1];
8685  else
8686  nextstarttime = endtimes[nvars-1];
8687 
8688  nextstarttime = MIN(nextstarttime, hmax);
8689 
8690  /* create capacity restriction row for current event point */
8691  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, curtime, j+1, endindex, cutsasconss) );
8692 
8693  /* create for all points in time between the current event point and next start event point a row if the free
8694  * capacity is still smaller than zero */
8695  for( t = curtime+1 ; t < nextstarttime; ++t )
8696  {
8697  /* add the capacity requirments for all job which end at the curtime */
8698  addEndingJobDemands(consdata, t, endtimes, endindices, &freecapacity, &endindex, nvars);
8699 
8700  if( freecapacity < 0 )
8701  {
8702  /* add constraint */
8703  SCIPdebugMsg(scip, "add capacity constraint at time %d\n", t);
8704 
8705  /* create capacity restriction row */
8706  SCIP_CALL( createCapacityRestriction(scip, cons, startindices, t, j+1, endindex, cutsasconss) );
8707  }
8708  else
8709  break;
8710  }
8711  }
8712  } /*lint --e{850}*/
8713 
8714  /* free all buffer arrays */
8715  SCIPfreeBufferArray(scip, &endindices);
8716  SCIPfreeBufferArray(scip, &startindices);
8717  SCIPfreeBufferArray(scip, &endtimes);
8718  SCIPfreeBufferArray(scip, &starttimes);
8719 
8720  return SCIP_OKAY;
8721 }
8722 
8723 /** creates LP rows corresponding to cumulative constraint; therefore, check each point in time if the maximal needed
8724  * capacity is larger than the capacity of the cumulative constraint
8725  * - for each necessary point in time:
8726  *
8727  * sum_j sum_t demand_j * x_{j,t} <= capacity
8728  *
8729  * where x(j,t) is the binary variables of job j at time t
8730  */
8731 static
8733  SCIP* scip, /**< SCIP data structure */
8734  SCIP_CONS* cons, /**< cumulative constraint */
8735  SCIP_Bool cutsasconss /**< should the cumulative constraint create the cuts as constraints? */
8736  )
8737 {
8738  SCIP_CONSDATA* consdata;
8739 
8740  consdata = SCIPconsGetData(cons);
8741  assert(consdata != NULL);
8742  assert(consdata->demandrows == NULL);
8743  assert(consdata->ndemandrows == 0);
8744 
8745  /* collect the linking constraints */
8746  if( consdata->linkingconss == NULL )
8747  {
8748  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8749  }
8750 
8751  SCIP_CALL( consCapacityConstraintsFinder(scip, cons, cutsasconss) );
8752 
8753  /* switch of separation for the cumulative constraint if linear constraints are add as cuts */
8754  if( cutsasconss )
8755  {
8756  if( SCIPconsIsInitial(cons) )
8757  {
8758  SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
8759  }
8760  if( SCIPconsIsSeparated(cons) )
8761  {
8762  SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
8763  }
8764  if( SCIPconsIsEnforced(cons) )
8765  {
8766  SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
8767  }
8768  }
8769 
8770  return SCIP_OKAY;
8771 }
8772 
8773 /** adds linear relaxation of cumulative constraint to the LP */
8774 static
8776  SCIP* scip, /**< SCIP data structure */
8777  SCIP_CONS* cons, /**< cumulative constraint */
8778  SCIP_Bool cutsasconss, /**< should the cumulative constraint create the cuts as constraints? */
8779  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
8780  )
8781 {
8782  SCIP_CONSDATA* consdata;
8783  int r;
8784 
8785  consdata = SCIPconsGetData(cons);
8786  assert(consdata != NULL);
8787 
8788  if( consdata->demandrows == NULL )
8789  {
8790  assert(consdata->ndemandrows == 0);
8791 
8792  SCIP_CALL( createRelaxation(scip, cons, cutsasconss) );
8793 
8794  return SCIP_OKAY;
8795  }
8796 
8797  for( r = 0; r < consdata->ndemandrows && !(*infeasible); ++r )
8798  {
8799  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8800  {
8801  assert(consdata->demandrows[r] != NULL);
8802  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, infeasible) );
8803  }
8804  }
8805 
8806  return SCIP_OKAY;
8807 }
8808 
8809 /** checks constraint for violation, and adds it as a cut if possible */
8810 static
8812  SCIP* scip, /**< SCIP data structure */
8813  SCIP_CONS* cons, /**< cumulative constraint to be separated */
8814  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8815  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8816  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8817  )
8818 { /*lint --e{715}*/
8819  SCIP_CONSDATA* consdata;
8820  int ncuts;
8821  int r;
8822 
8823  assert(scip != NULL);
8824  assert(cons != NULL);
8825  assert(separated != NULL);
8826  assert(cutoff != NULL);
8827 
8828  *separated = FALSE;
8829  *cutoff = FALSE;
8830 
8831  consdata = SCIPconsGetData(cons);
8832  assert(consdata != NULL);
8833 
8834  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8835 
8836  if( consdata->demandrows == NULL )
8837  {
8838  assert(consdata->ndemandrows == 0);
8839 
8840  SCIP_CALL( createRelaxation(scip, cons, FALSE) );
8841 
8842  return SCIP_OKAY;
8843  }
8844 
8845  ncuts = 0;
8846 
8847  /* check each row that is not contained in LP */
8848  for( r = 0; r < consdata->ndemandrows; ++r )
8849  {
8850  if( !SCIProwIsInLP(consdata->demandrows[r]) )
8851  {
8852  SCIP_Real feasibility;
8853 
8854  if( sol != NULL )
8855  feasibility = SCIPgetRowSolFeasibility(scip, consdata->demandrows[r], sol);
8856  else
8857  feasibility = SCIPgetRowLPFeasibility(scip, consdata->demandrows[r]);
8858 
8859  if( SCIPisFeasNegative(scip, feasibility) )
8860  {
8861  SCIP_CALL( SCIPaddRow(scip, consdata->demandrows[r], FALSE, cutoff) );
8862  if ( *cutoff )
8863  {
8864  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8865  return SCIP_OKAY;
8866  }
8867  *separated = TRUE;
8868  ncuts++;
8869  }
8870  }
8871  }
8872 
8873  if( ncuts > 0 )
8874  {
8875  SCIPdebugMsg(scip, "cumulative constraint <%s> separated %d cuts\n", SCIPconsGetName(cons), ncuts);
8876 
8877  /* if successful, reset age of constraint */
8878  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8879  (*separated) = TRUE;
8880  }
8881 
8882  return SCIP_OKAY;
8883 }
8884 
8885 /** checks constraint for violation, and adds it as a cut if possible */
8886 static
8888  SCIP* scip, /**< SCIP data structure */
8889  SCIP_CONS* cons, /**< logic or constraint to be separated */
8890  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
8891  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
8892  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
8893  )
8894 {
8895  SCIP_CONSDATA* consdata;
8896  SCIP_ROW* row;
8897  SCIP_Real minfeasibility;
8898  int r;
8899 
8900  assert(scip != NULL);
8901  assert(cons != NULL);
8902  assert(separated != NULL);
8903  assert(cutoff != NULL);
8904 
8905  *separated = FALSE;
8906  *cutoff = FALSE;
8907 
8908  consdata = SCIPconsGetData(cons);
8909  assert(consdata != NULL);
8910 
8911  SCIPdebugMsg(scip, "separate cumulative constraint <%s>\n", SCIPconsGetName(cons));
8912 
8913  /* collect the linking constraints */
8914  if( consdata->linkingconss == NULL )
8915  {
8916  SCIP_CALL( consdataCollectLinkingCons(scip, consdata) );
8917  }
8918 
8919  if( !consdata->covercuts )
8920  {
8921  SCIP_CALL( createCoverCuts(scip, cons) );
8922  }
8923 
8924  row = NULL;
8925  minfeasibility = SCIPinfinity(scip);
8926 
8927  /* check each row of small covers that is not contained in LP */
8928  for( r = 0; r < consdata->nscoverrows; ++r )
8929  {
8930  if( !SCIProwIsInLP(consdata->scoverrows[r]) )
8931  {
8932  SCIP_Real feasibility;
8933 
8934  assert(consdata->scoverrows[r] != NULL);
8935  if( sol != NULL )
8936  feasibility = SCIPgetRowSolFeasibility(scip, consdata->scoverrows[r], sol);
8937  else
8938  feasibility = SCIPgetRowLPFeasibility(scip, consdata->scoverrows[r]);
8939 
8940  if( minfeasibility > feasibility )
8941  {
8942  minfeasibility = feasibility;
8943  row = consdata->scoverrows[r];
8944  }
8945  }
8946  }
8947 
8948  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8949 
8950  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8951  {
8952  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8953  SCIPconsGetName(cons), minfeasibility);
8954 
8955  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8956  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8957  if ( *cutoff )
8958  return SCIP_OKAY;
8959  (*separated) = TRUE;
8960  }
8961 
8962  minfeasibility = SCIPinfinity(scip);
8963  row = NULL;
8964 
8965  /* check each row of small covers that is not contained in LP */
8966  for( r = 0; r < consdata->nbcoverrows; ++r )
8967  {
8968  if( !SCIProwIsInLP(consdata->bcoverrows[r]) )
8969  {
8970  SCIP_Real feasibility;
8971 
8972  assert(consdata->bcoverrows[r] != NULL);
8973  if( sol != NULL )
8974  feasibility = SCIPgetRowSolFeasibility(scip, consdata->bcoverrows[r], sol);
8975  else
8976  feasibility = SCIPgetRowLPFeasibility(scip, consdata->bcoverrows[r]);
8977 
8978  if( minfeasibility > feasibility )
8979  {
8980  minfeasibility = feasibility;
8981  row = consdata->bcoverrows[r];
8982  }
8983  }
8984  }
8985 
8986  assert(!SCIPisFeasNegative(scip, minfeasibility) || row != NULL);
8987 
8988  if( row != NULL && SCIPisFeasNegative(scip, minfeasibility) )
8989  {
8990  SCIPdebugMsg(scip, "cumulative constraint <%s> separated 1 cover cut with feasibility %g\n",
8991  SCIPconsGetName(cons), minfeasibility);
8992 
8993  assert(row != NULL);
8994  SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
8995  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8996  if ( *cutoff )
8997  return SCIP_OKAY;
8998  (*separated) = TRUE;
8999  }
9000 
9001  return SCIP_OKAY;
9002 }
9003 
9004 /** this method creates a row for time point @p curtime which ensures the capacity restriction of the cumulative constraint */
9005 static
9007  SCIP* scip, /**< SCIP data structure */
9008  SCIP_CONS* cons, /**< constraint to be checked */
9009  int* startindices, /**< permutation with rspect to the start times */
9010  int curtime, /**< current point in time */
9011  int nstarted, /**< number of jobs that start before the curtime or at curtime */
9012  int nfinished, /**< number of jobs that finished before curtime or at curtime */
9013  SCIP_Bool lower, /**< shall cuts be created due to lower or upper bounds? */
9014  SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9015  )
9016 {
9017  SCIP_CONSDATA* consdata;
9018  char name[SCIP_MAXSTRLEN];
9019  int lhs; /* left hand side of constraint */
9020 
9021  SCIP_VAR** activevars;
9022  SCIP_ROW* row;
9023 
9024  int v;
9025 
9026  assert(nstarted > nfinished);
9027 
9028  consdata = SCIPconsGetData(cons);
9029  assert(consdata != NULL);
9030  assert(consdata->nvars > 0);
9031 
9032  SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nstarted-nfinished) );
9033 
9034  SCIP_CALL( collectIntVars(scip, consdata, &activevars, startindices, curtime, nstarted, nfinished, lower, &lhs ) );
9035 
9036  if( lower )
9037  {
9038  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "lower(%d)", curtime);
9039 
9040  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, (SCIP_Real) lhs, SCIPinfinity(scip),
9041  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9042  }
9043  else
9044  {
9045  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "upper(%d)", curtime);
9046  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) lhs,
9047  TRUE, FALSE, SCIPconsIsRemovable(cons)) );
9048  }
9049 
9050  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
9051 
9052  for( v = 0; v < nstarted - nfinished; ++v )
9053  {
9054  SCIP_CALL( SCIPaddVarToRow(scip, row, activevars[v], 1.0) );
9055  }
9056 
9057  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
9058  SCIPdebug( SCIP_CALL(SCIPprintRow(scip, row, NULL)) );
9059 
9060  SCIP_CALL( SCIPaddRow(scip, row, TRUE, cutoff) );
9061 
9062  SCIP_CALL( SCIPreleaseRow(scip, &row) );
9063 
9064  /* free buffers */
9065  SCIPfreeBufferArrayNull(scip, &activevars);
9066 
9067  return SCIP_OKAY;
9068 }
9069 
9070 /** checks constraint for violation, and adds it as a cut if possible */
9071 static
9073  SCIP* scip, /**< SCIP data structure */
9074  SCIP_CONS* cons, /**< cumulative constraint to be separated */
9075  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
9076  SCIP_Bool lower, /**< shall cuts be created according to lower bounds? */
9077  SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
9078  SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was detected */
9079  )
9080 {
9081  SCIP_CONSDATA* consdata;
9082 
9083  int* starttimes; /* stores when each job is starting */
9084  int* endtimes; /* stores when each job ends */
9085  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
9086  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
9087 
9088  int nvars; /* number of activities for this constraint */
9089  int freecapacity; /* remaining capacity */
9090  int curtime; /* point in time which we are just checking */
9091  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
9092 
9093  int hmin;
9094  int hmax;
9095  int j;
9096 
9097  assert(scip != NULL);
9098  assert(cons != NULL);
9099 
9100  consdata = SCIPconsGetData(cons);
9101  assert(consdata != NULL);
9102 
9103  nvars = consdata->nvars;
9104 
9105  /* if no activities are associated with this cumulative then this constraint is redundant */
9106  if( nvars <= 1 )
9107  return SCIP_OKAY;
9108 
9109  assert(consdata->vars != NULL);
9110 
9111  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
9112  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
9113  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
9114  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
9115 
9116  SCIPdebugMsg(scip, "create sorted event points for cumulative constraint <%s> with %d jobs\n",
9117  SCIPconsGetName(cons), nvars);
9118 
9119  /* create event point arrays */
9120  createSelectedSortedEventpointsSol(scip, consdata, sol, starttimes, endtimes, startindices, endindices, &nvars, lower);
9121 
9122  /* now nvars might be smaller than before! */
9123 
9124  endindex = 0;
9125  freecapacity = consdata->capacity;
9126  hmin = consdata->hmin;
9127  hmax = consdata->hmax;
9128 
9129  /* check each startpoint of a job whether the capacity is kept or not */
9130  for( j = 0; j < nvars && !(*cutoff); ++j )
9131  {
9132  curtime = starttimes[j];
9133 
9134  if( curtime >= hmax )
9135  break;
9136 
9137  /* remove the capacity requirements for all job which start at the curtime */
9138  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
9139 
9140  /* add the capacity requirments for all job which end at the curtime */
9141  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
9142 
9143  assert(freecapacity <= consdata->capacity);
9144  assert(endindex <= nvars);
9145 
9146  /* endindex - points to the next job which will finish */
9147  /* j - points to the last job that has been released */
9148 
9149  /* if free capacity is smaller than zero, then add rows to the LP */
9150  if( freecapacity < 0 && curtime >= hmin)
9151  {
9152  /* create capacity restriction row for current event point */
9153  SCIP_CALL( createCapacityRestrictionIntvars(scip, cons, startindices, curtime, j+1, endindex, lower, cutoff) );
9154  *separated = TRUE;
9155  }
9156  } /*lint --e{850}*/
9157 
9158  /* free all buffer arrays */
9159  SCIPfreeBufferArray(scip, &endindices);
9160  SCIPfreeBufferArray(scip, &startindices);
9161  SCIPfreeBufferArray(scip, &endtimes);
9162  SCIPfreeBufferArray(scip, &starttimes);
9163 
9164  return SCIP_OKAY;
9165 }
9166 
9167 /**@} */
9168 
9169 
9170 /**@name Presolving
9171  *
9172  * @{
9173  */
9174 
9175 #ifndef NDEBUG
9176 /** returns TRUE if all demands are smaller than the capacity of the cumulative constraint and if the total demand is
9177  * correct
9178  */
9179 static
9181  SCIP* scip, /**< SCIP data structure */
9182  SCIP_CONS* cons /**< constraint to be checked */
9183  )
9184 {
9185  SCIP_CONSDATA* consdata;
9186  int capacity;
9187  int nvars;
9188  int j;
9189 
9190  assert(scip != NULL);
9191  assert(cons != NULL);
9192 
9193  consdata = SCIPconsGetData(cons);
9194  assert(consdata != NULL);
9195 
9196  nvars = consdata->nvars;
9197 
9198  /* if no activities are associated with this cumulative then this constraint is not infeasible, return */
9199  if( nvars <= 1 )
9200  return TRUE;
9201 
9202  assert(consdata->vars != NULL);
9203  capacity = consdata->capacity;
9204 
9205  /* check each activity: if demand is larger than capacity the problem is infeasible */
9206  for ( j = 0; j < nvars; ++j )
9207  {
9208  if( consdata->demands[j] > capacity )
9209  return FALSE;
9210  }
9211 
9212  return TRUE;
9213 }
9214 #endif
9215 
9216 /** delete constraint if it consists of at most one job
9217  *
9218  * @todo this method needs to be adjusted w.r.t. effective horizon
9219  */
9220 static
9222  SCIP* scip, /**< SCIP data structure */
9223  SCIP_CONS* cons, /**< constraint to propagate */
9224  int* ndelconss, /**< pointer to store the number of deleted constraints */
9225  SCIP_Bool* cutoff /**< pointer to store if the constraint is infeasible */
9226  )
9227 {
9228  SCIP_CONSDATA* consdata;
9229 
9230  assert(scip != NULL);
9231  assert(cons != NULL);
9232 
9233  consdata = SCIPconsGetData(cons);
9234  assert(consdata != NULL);
9235 
9236  if( consdata->nvars == 0 )
9237  {
9238  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9239 
9240  SCIP_CALL( SCIPdelCons(scip, cons) );
9241  (*ndelconss)++;
9242  }
9243  else if( consdata->nvars == 1 )
9244  {
9245  if( consdata->demands[0] > consdata->capacity )
9246  (*cutoff) = TRUE;
9247  else
9248  {
9249  SCIPdebugMsg(scip, "delete cumulative constraints <%s>\n", SCIPconsGetName(cons));
9250 
9251  SCIP_CALL( SCIPdelCons(scip, cons) );
9252  (*ndelconss)++;
9253  }
9254  }
9255 
9256  return SCIP_OKAY;
9257 }
9258 
9259 /** remove jobs which have a duration or demand of zero (zero energy) or lay outside the efficient horizon [hmin, hmax);
9260  * this is done in the SCIP_DECL_CONSINITPRE() callback
9261  */
9262 static
9264  SCIP* scip, /**< SCIP data structure */
9265  SCIP_CONS* cons /**< constraint to propagate */
9266  )
9267 {
9268  SCIP_CONSDATA* consdata;
9269  SCIP_VAR* var;
9270  int demand;
9271  int duration;
9272  int hmin;
9273  int hmax;
9274  int est;
9275  int lct;
9276  int j;
9277 
9278  assert(scip != NULL);
9279  assert(cons != NULL);
9280 
9281  consdata = SCIPconsGetData(cons);
9282  assert(consdata != NULL);
9283 
9284  hmin = consdata->hmin;
9285  hmax = consdata->hmax;
9286 
9287  SCIPdebugMsg(scip, "check for irrelevant jobs within cumulative constraint <%s>[%d,%d)\n",
9288  SCIPconsGetName(cons), hmin, hmax);
9289 
9290  for( j = consdata->nvars-1; j >= 0; --j )
9291  {
9292  var = consdata->vars[j];
9293  demand = consdata->demands[j];
9294  duration = consdata->durations[j];
9295 
9296  /* earliest completion time (ect) and latest start time (lst) */
9297  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
9298  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + duration;
9299 
9300  if( demand == 0 || duration == 0 )
9301  {
9302  /* jobs with zero demand or zero duration can be removed */
9303  SCIPdebugMsg(scip, " remove variable <%s> due to zero %s\n",
9304  SCIPvarGetName(var), demand == 0 ? "demand" : "duration");
9305 
9306  /* remove variable form constraint */
9307  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9308  }
9309  else if( est >= hmax || lct <= hmin )
9310  {
9311  SCIPdebugMsg(scip, " remove variable <%s>[%d,%d] with duration <%d>\n",
9312  SCIPvarGetName(var), est, lct - duration, duration);
9313 
9314  /* delete variable at the given position */
9315  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9316 
9317  /* for the statistic we count the number of jobs which are irrelevant */
9318  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
9319  }
9320  }
9321 
9322  return SCIP_OKAY;
9323 }
9324 
9325 /** adjust bounds of over sizeed job (the demand is larger than the capacity) */
9326 static
9328  SCIP* scip, /**< SCIP data structure */
9329  SCIP_CONSDATA* consdata, /**< constraint data */
9330  int pos, /**< position of job in the consdata */
9331  int* nchgbds, /**< pointer to store the number of changed bounds */
9332  int* naddconss, /**< pointer to store the number of added constraints */
9333  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9334  )
9335 {
9336  SCIP_VAR* var;
9337  SCIP_Bool tightened;
9338  int duration;
9339  int ect;
9340  int lst;
9341 
9342  assert(scip != NULL);
9343 
9344  /* zero energy jobs should be removed already */
9345  assert(consdata->durations[pos] > 0);
9346  assert(consdata->demands[pos] > 0);
9347 
9348  var = consdata->vars[pos];
9349  assert(var != NULL);
9350  duration = consdata->durations[pos];
9351 
9352  /* jobs with a demand greater than the the capacity have to moved outside the time interval [hmin,hmax) */
9353  SCIPdebugMsg(scip, " variable <%s>: demand <%d> is larger than the capacity <%d>\n",
9354  SCIPvarGetName(var), consdata->demands[pos], consdata->capacity);
9355 
9356  /* earliest completion time (ect) and latest start time (lst) */
9357  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration;
9358  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
9359 
9360  /* the jobs has to have an overlap with the efficient horizon otherwise it would be already removed */
9361  if( ect - duration >= consdata->hmax || lst + duration <= consdata->hmin)
9362  return SCIP_OKAY;
9363 
9364  if( ect > consdata->hmin && lst < consdata->hmax )
9365  {
9366  /* the job will at least run partly in the time interval [hmin,hmax) this means the problem is infeasible */
9367  *cutoff = TRUE;
9368  }
9369  else if( lst < consdata->hmax )
9370  {
9371  /* move the latest start time of this job in such a way that it finishes before or at hmin */
9372  SCIP_CALL( SCIPtightenVarUb(scip, var, (SCIP_Real)(consdata->hmin - duration), TRUE, cutoff, &tightened) );
9373  assert(tightened);
9374  assert(!(*cutoff));
9375  (*nchgbds)++;
9376  }
9377  else if( ect > consdata->hmin )
9378  {
9379  /* move the earliest start time of this job in such a way that it starts after or at hmax */
9380  SCIP_CALL( SCIPtightenVarLb(scip, var, (SCIP_Real)(consdata->hmax), TRUE, cutoff, &tightened) );
9381  assert(tightened);
9382  assert(!(*cutoff));
9383  (*nchgbds)++;
9384  }
9385  else
9386  {
9387  /* this job can run before or after the time interval [hmin,hmax) thus we create a bound disjunction
9388  * constraint to ensure that it does not overlap with the time interval [hmin,hmax); that is:
9389  *
9390  * (var <= hmin - duration) /\ (var >= hmax)
9391  */
9392  SCIP_CONS* cons;
9393 
9394  SCIP_VAR* vartuple[2];
9395  SCIP_BOUNDTYPE boundtypetuple[2];
9396  SCIP_Real boundtuple[2];
9397 
9398  char name[SCIP_MAXSTRLEN];
9399  int leftbound;
9400  int rightbound;
9401 
9402  leftbound = consdata->hmin - duration;
9403  rightbound = consdata->hmax;
9404 
9405  /* allocate temporary memory for arrays */
9406  vartuple[0] = var;
9407  vartuple[1] = var;
9408  boundtuple[0] = (SCIP_Real)leftbound;
9409  boundtuple[1] = (SCIP_Real)rightbound;
9410  boundtypetuple[0] = SCIP_BOUNDTYPE_UPPER;
9411  boundtypetuple[1] = SCIP_BOUNDTYPE_LOWER;
9412 
9413  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s<=%d or %s >= %d",
9414  SCIPvarGetName(var), leftbound, SCIPvarGetName(var), rightbound);
9415 
9416  /* create and add bounddisjunction constraint */
9417  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vartuple, boundtypetuple, boundtuple,
9418  TRUE, FALSE, TRUE, TRUE /*check*/, TRUE/*prop*/, FALSE, FALSE, FALSE, FALSE, FALSE) );
9419 
9420  SCIPdebugPrintCons(scip, cons, NULL);
9421 
9422  /* add and release the new constraint */
9423  SCIP_CALL( SCIPaddCons(scip, cons) );
9424  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9425  (*naddconss)++;
9426  }
9427 
9428  return SCIP_OKAY;
9429 }
9430 
9431 /** try to removed over sizeed jobs (the demand is larger than the capacity) */
9432 static
9434  SCIP* scip, /**< SCIP data structure */
9435  SCIP_CONS* cons, /**< constraint */
9436  int* nchgbds, /**< pointer to store the number of changed bounds */
9437  int* nchgcoefs, /**< pointer to store the number of changed coefficient */
9438  int* naddconss, /**< pointer to store the number of added constraints */
9439  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
9440  )
9441 {
9442  SCIP_CONSDATA* consdata;
9443  int capacity;
9444  int j;
9445 
9446  consdata = SCIPconsGetData(cons);
9447  assert(consdata != NULL);
9448 
9449  /* if a cutoff was already detected just return */
9450  if( *cutoff )
9451  return SCIP_OKAY;
9452 
9453  capacity = consdata->capacity;
9454 
9455  for( j = consdata->nvars-1; j >= 0 && !(*cutoff); --j )
9456  {
9457  if( consdata->demands[j] > capacity )
9458  {
9459  SCIP_CALL( adjustOversizedJobBounds(scip, consdata, j, nchgbds, naddconss, cutoff) );
9460 
9461  /* remove variable form constraint */
9462  SCIP_CALL( consdataDeletePos(scip, consdata, cons, j) );
9463  (*nchgcoefs)++;
9464  }
9465  }
9466 
9467  SCIPdebugMsg(scip, "cumulative constraint <%s> has %d jobs left, cutoff %u\n", SCIPconsGetName(cons), consdata->nvars, *cutoff);
9468 
9469  return SCIP_OKAY;
9470 }
9471 
9472 /** fix integer variable to upper bound if the rounding locks and the object coefficient are in favor of that */
9473 static
9475  SCIP* scip, /**< SCIP data structure */
9476  SCIP_VAR* var, /**< integer variable to fix */
9477  SCIP_Bool uplock, /**< has thet start time variable a up lock */
9478  int* nfixedvars /**< pointer to store the number fixed variables */
9479  )
9480 {
9481  SCIP_Bool infeasible;
9482  SCIP_Bool tightened;
9483  SCIP_Bool roundable;
9484 
9485  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9486  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9487  */
9488  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9489  return SCIP_OKAY;
9490 
9491  /* rounding the variable to the upper bound is only a feasible dual reduction if the cumulative constraint
9492  * handler is the only one locking that variable up
9493  */
9494  assert(uplock == TRUE || uplock == FALSE);
9495  assert((int)TRUE == 1); /*lint !e506*/
9496  assert((int)FALSE == 0); /*lint !e506*/
9497 
9498  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > (int)(uplock) )
9499  return SCIP_OKAY;
9500 
9501  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
9502 
9503  /* rounding the integer variable up is only a valid dual reduction if the object coefficient is zero or negative
9504  * (the transformed problem is always a minimization problem)
9505  */
9506  if( !roundable )
9507  return SCIP_OKAY;
9508 
9509  SCIPdebugMsg(scip, "try fixing variable <%s>[%g,%g] to upper bound %g\n", SCIPvarGetName(var),
9511 
9512  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &tightened) );
9513  assert(!infeasible);
9514 
9515  if( tightened )
9516  {
9517  SCIPdebugMsg(scip, "fix variable <%s> to upper bound %g\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var));
9518  (*nfixedvars)++;
9519  }
9520 
9521  return SCIP_OKAY;
9522 }
9523 
9524 /** fix integer variable to lower bound if the rounding locks and the object coefficient are in favor of that */
9525 static
9527  SCIP* scip, /**< SCIP data structure */
9528  SCIP_VAR* var, /**< integer variable to fix */
9529  SCIP_Bool downlock, /**< has the variable a down lock */
9530  int* nfixedvars /**< pointer to store the number fixed variables */
9531  )
9532 {
9533  SCIP_Bool infeasible;
9534  SCIP_Bool tightened;
9535  SCIP_Bool roundable;
9536 
9537  /* if SCIP is in probing mode or repropagation we cannot perform this dual reductions since this dual reduction
9538  * would/could end in an implication which can lead to cutoff of the/all optimal solution
9539  */
9540  if( SCIPinProbing(scip) || SCIPinRepropagation(scip) )
9541  return SCIP_OKAY;
9542 
9543  /* rounding the variable to the lower bound is only a feasible dual reduction if the cumulative constraint
9544  * handler is the only one locking that variable down
9545  */
9546  assert(downlock == TRUE || downlock == FALSE);
9547  assert((int)TRUE == 1); /*lint !e506*/
9548  assert((int)FALSE == 0); /*lint !e506*/
9549 
9550  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) > (int)(downlock) )
9551  return SCIP_OKAY;
9552 
9553  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
9554 
9555  /* is it possible, to round variable down w.r.t. objective function? */
9556  if( !roundable )
9557  return SCIP_OKAY;
9558 
9559  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &tightened) );
9560  assert(!infeasible);
9561 
9562  if( tightened )
9563  {
9564  SCIPdebugMsg(scip, "fix variable <%s> to lower bound %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var));
9565  (*nfixedvars)++;
9566  }
9567 
9568  return SCIP_OKAY;
9569 }
9570 
9571 /** normalize cumulative condition */
9572 static
9574  SCIP* scip, /**< SCIP data structure */
9575  int nvars, /**< number of start time variables (activities) */
9576  int* demands, /**< array of demands */
9577  int* capacity, /**< pointer to store the changed cumulative capacity */
9578  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9579  int* nchgsides /**< pointer to count number of side changes */
9580  )
9581 { /*lint --e{715}*/
9582  SCIP_Longint gcd;
9583  int mindemand1;
9584  int mindemand2;
9585  int v;
9586 
9587  if( *capacity == 1 || nvars <= 1 )
9588  return;
9589 
9590  assert(demands[nvars-1] <= *capacity);
9591  assert(demands[nvars-2] <= *capacity);
9592 
9593  gcd = (SCIP_Longint)demands[nvars-1];
9594  mindemand1 = MIN(demands[nvars-1], demands[nvars-2]);
9595  mindemand2 = MAX(demands[nvars-1], demands[nvars-2]);
9596 
9597  for( v = nvars-2; v >= 0 && (gcd >= 2 || mindemand1 + mindemand2 > *capacity); --v )
9598  {
9599  assert(mindemand1 <= mindemand2);
9600  assert(demands[v] <= *capacity);
9601 
9602  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)demands[v]);
9603 
9604  if( mindemand1 > demands[v] )
9605  {
9606  mindemand2 = mindemand1;
9607  mindemand1 = demands[v];
9608  }
9609  else if( mindemand2 > demands[v] )
9610  mindemand2 = demands[v];
9611  }
9612 
9613  if( mindemand1 + mindemand2 > *capacity )
9614  {
9615  SCIPdebugMsg(scip, "update cumulative condition (%d + %d > %d) to unary cumulative condition\n", mindemand1, mindemand2, *capacity);
9616 
9617  for( v = 0; v < nvars; ++v )
9618  demands[v] = 1;
9619 
9620  (*capacity) = 1;
9621 
9622  (*nchgcoefs) += nvars;
9623  (*nchgsides)++;
9624  }
9625  else if( gcd >= 2 )
9626  {
9627  SCIPdebugMsg(scip, "cumulative condition: dividing demands by %" SCIP_LONGINT_FORMAT "\n", gcd);
9628 
9629  for( v = 0; v < nvars; ++v )
9630  demands[v] /= (int) gcd;
9631 
9632  (*capacity) /= (int) gcd;
9633 
9634  (*nchgcoefs) += nvars;
9635  (*nchgsides)++;
9636  }
9637 }
9638 
9639 /** divides demands by their greatest common divisor and divides capacity by the same value, rounding down the result;
9640  * in case the the smallest demands add up to more than the capacity we reductions all demands to one as well as the
9641  * capacity since in that case none of the jobs can run in parallel
9642  */
9643 static
9644 void normalizeDemands(
9645  SCIP* scip, /**< SCIP data structure */
9646  SCIP_CONS* cons, /**< cumulative constraint */
9647  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9648  int* nchgsides /**< pointer to count number of side changes */
9649  )
9650 {
9651  SCIP_CONSDATA* consdata;
9652  int capacity;
9653 
9654  assert(nchgcoefs != NULL);
9655  assert(nchgsides != NULL);
9656  assert(!SCIPconsIsModifiable(cons));
9657 
9658  consdata = SCIPconsGetData(cons);
9659  assert(consdata != NULL);
9660 
9661  if( consdata->normalized )
9662  return;
9663 
9664  capacity = consdata->capacity;
9665 
9666  /**@todo sort items w.r.t. the demands, because we can stop earlier if the smaller weights are evaluated first */
9667 
9668  normalizeCumulativeCondition(scip, consdata->nvars, consdata->demands, &consdata->capacity, nchgcoefs, nchgsides);
9669 
9670  consdata->normalized = TRUE;
9671 
9672  if( capacity > consdata->capacity )
9673  consdata->varbounds = FALSE;
9674 }
9675 
9676 /** computes for the given cumulative condition the effective horizon */
9677 static
9679  SCIP* scip, /**< SCIP data structure */
9680  int nvars, /**< number of variables (jobs) */
9681  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9682  int* durations, /**< array containing corresponding durations */
9683  int* demands, /**< array containing corresponding demands */
9684  int capacity, /**< available cumulative capacity */
9685  int* hmin, /**< pointer to store the left bound of the effective horizon */
9686  int* hmax, /**< pointer to store the right bound of the effective horizon */
9687  int* split /**< point were the cumulative condition can be split */
9688  )
9689 {
9690  SCIP_PROFILE* profile;
9691 
9692  /* create empty resource profile with infinity resource capacity */
9693  SCIP_CALL( SCIPprofileCreate(&profile, INT_MAX) );
9694 
9695  /* create worst case resource profile */
9696  SCIP_CALL_FINALLY( SCIPcreateWorstCaseProfile(scip, profile, nvars, vars, durations, demands), SCIPprofileFree(&profile) );
9697 
9698  /* print resource profile in if SCIP_DEBUG is defined */
9699  SCIPdebug( SCIPprofilePrint(profile, SCIPgetMessagehdlr(scip), NULL) );
9700 
9701  /* computes the first time point where the resource capacity can be violated */
9702  (*hmin) = SCIPcomputeHmin(scip, profile, capacity);
9703 
9704  /* computes the first time point where the resource capacity is satisfied for sure */
9705  (*hmax) = SCIPcomputeHmax(scip, profile, capacity);
9706 
9707  (*split) = (*hmax);
9708 
9709  if( *hmin < *hmax && !SCIPinRepropagation(scip) )
9710  {
9711  int* timepoints;
9712  int* loads;
9713  int ntimepoints;
9714  int t;
9715 
9716  /* If SCIP is repropagating the root node, it is not possible to decompose the constraints. This is the case since
9717  * the conflict analysis stores the constraint pointer for bound changes made by this constraint. These pointer
9718  * are used during the resolve propagation phase to explain bound changes. If we would decompose certain jobs into
9719  * a new cumulative constraint, the "old" pointer is not valid. More precise, the "old" constraint is not able to
9720  * explain the certain "old" bound changes
9721  */
9722 
9723  /* search for time points */
9724  ntimepoints = SCIPprofileGetNTimepoints(profile);
9725  timepoints = SCIPprofileGetTimepoints(profile);
9726  loads = SCIPprofileGetLoads(profile);
9727 
9728  /* 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 */
9729  for( t = 0; t < ntimepoints; ++t )
9730  {
9731  /* ignore all time points before the effective horizon */
9732  if( timepoints[t] <= *hmin )
9733  continue;
9734 
9735  /* ignore all time points after the effective horizon */
9736  if( timepoints[t] >= *hmax )
9737  break;
9738 
9739  /* check if the current time point does not exceed the capacity w.r.t. worst case resource profile; if so we
9740  * can split the cumulative constraint into two cumulative constraints
9741  */
9742  if( loads[t] <= capacity )
9743  {
9744  (*split) = timepoints[t];
9745  break;
9746  }
9747  }
9748  }
9749 
9750  /* free worst case profile */
9751  SCIPprofileFree(&profile);
9752 
9753  return SCIP_OKAY;
9754 }
9755 
9756 /** creates and adds a cumulative constraint */
9757 static
9759  SCIP* scip, /**< SCIP data structure */
9760  const char* name, /**< name of constraint */
9761  int nvars, /**< number of variables (jobs) */
9762  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
9763  int* durations, /**< array containing corresponding durations */
9764  int* demands, /**< array containing corresponding demands */
9765  int capacity, /**< available cumulative capacity */
9766  int hmin, /**< left bound of time axis to be considered (including hmin) */
9767  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9768  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9769  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9770  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9771  * Usually set to TRUE. */
9772  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9773  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9774  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9775  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9776  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9777  * Usually set to TRUE. */
9778  SCIP_Bool local, /**< is constraint only valid locally?
9779  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9780  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9781  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9782  * adds coefficients to this constraint. */
9783  SCIP_Bool dynamic, /**< is constraint subject to aging?
9784  * Usually set to FALSE. Set to TRUE for own cuts which
9785  * are seperated as constraints. */
9786  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9787  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9788  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9789  * if it may be moved to a more global node?
9790  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9791  )
9792 {
9793  SCIP_CONS* cons;
9794 
9795  /* creates cumulative constraint and adds it to problem */
9796  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, nvars, vars, durations, demands, capacity,
9797  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9798 
9799  /* adjust the effective time horizon of the new constraint */
9800  SCIP_CALL( SCIPsetHminCumulative(scip, cons, hmin) );
9801  SCIP_CALL( SCIPsetHmaxCumulative(scip, cons, hmax) );
9802 
9803  /* add and release new cumulative constraint */
9804  SCIP_CALL( SCIPaddCons(scip, cons) );
9805  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9806 
9807  return SCIP_OKAY;
9808 }
9809 
9810 /** computes the effective horizon and checks if the constraint can be decompsed */
9811 static
9813  SCIP* scip, /**< SCIP data structure */
9814  SCIP_CONS* cons, /**< cumulative constraint */
9815  int* ndelconss, /**< pointer to store the number of deleted constraints */
9816  int* naddconss, /**< pointer to store the number of added constraints */
9817  int* nchgsides /**< pointer to store the number of changed sides */
9818  )
9819 {
9820  SCIP_CONSDATA* consdata;
9821  int hmin;
9822  int hmax;
9823  int split;
9824 
9825  consdata = SCIPconsGetData(cons);
9826  assert(consdata != NULL);
9827 
9828  if( consdata->nvars <= 1 )
9829  return SCIP_OKAY;
9830 
9831  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, consdata->nvars, consdata->vars,
9832  consdata->durations, consdata->demands, consdata->capacity, &hmin, &hmax, &split) );
9833 
9834  /* check if this time point improves the effective horizon */
9835  if( consdata->hmin < hmin )
9836  {
9837  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmin <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmin, hmin);
9838 
9839  consdata->hmin = hmin;
9840  (*nchgsides)++;
9841  }
9842 
9843  /* check if this time point improves the effective horizon */
9844  if( consdata->hmax > hmax )
9845  {
9846  SCIPdebugMsg(scip, "cumulative constraint <%s> adjust hmax <%d> -> <%d>\n", SCIPconsGetName(cons), consdata->hmax, hmax);
9847  consdata->hmax = hmax;
9848  (*nchgsides)++;
9849  }
9850 
9851  /* check if the constraint is redundant */
9852  if( consdata->hmax <= consdata->hmin )
9853  {
9854  SCIPdebugMsg(scip, "constraint <%s> is redundant since hmax(%d) <= hmin(%d)\n",
9855  SCIPconsGetName(cons), consdata->hmax, consdata->hmin);
9856 
9857  SCIP_CALL( SCIPdelCons(scip, cons) );
9858  (*ndelconss)++;
9859  }
9860  else if( consdata->hmin < split && split < consdata->hmax )
9861  {
9862  char name[SCIP_MAXSTRLEN];
9863  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "(%s)'", SCIPconsGetName(cons));
9864 
9865  SCIPdebugMsg(scip, "split cumulative constraint <%s>[%d,%d) with %d jobs at time point %d\n",
9866  SCIPconsGetName(cons), consdata->hmin, consdata->hmax, consdata->nvars, split);
9867 
9868  assert(split < consdata->hmax);
9869 
9870  /* creates cumulative constraint and adds it to problem */
9871  SCIP_CALL( createConsCumulative(scip, name, consdata->nvars, consdata->vars,
9872  consdata->durations, consdata->demands, consdata->capacity, split, consdata->hmax,
9875 
9876  /* adjust the effective time horizon of the constraint */
9877  consdata->hmax = split;
9878 
9879  assert(consdata->hmin < consdata->hmax);
9880 
9881  /* for the statistic we count the number of time we decompose a cumulative constraint */
9883  (*naddconss)++;
9884  }
9885 
9886  return SCIP_OKAY;
9887 }
9888 
9889 
9890 /** presolve cumulative condition w.r.t. the earlier start times (est) and the hmin of the effective horizon
9891  *
9892  * (1) If the latest completion time (lct) of a job is smaller or equal than hmin, the corresponding job can be removed
9893  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
9894  *
9895  * (2) If the latest start time (lst) of a job is smaller or equal than hmin it follows that the this jobs can run
9896  * before the effective horizon or it overlaps with the effective horizon such that hmin in included. Hence, the
9897  * down-lock of the corresponding start time variable can be removed.
9898  *
9899  * (3) If the earlier completion time (ect) of a job is smaller or equal than hmin, the cumulative is the only one
9900  * locking the corresponding variable down, and the objective coefficient of the start time variable is not
9901  * negative, than the job can be dual fixed to its earlier start time (est).
9902  *
9903  * (4) If the earlier start time (est) of job is smaller than the hmin, the cumulative is the only one locking the
9904  * corresponding variable down, and the objective coefficient of the start time variable is not negative, than
9905  * removing the values {est+1,...,hmin} form variable domain is dual feasible.
9906  *
9907  * (5) If the earlier start time (est) of job is smaller than the smallest earlier completion times of all other jobs
9908  * (lets denote this with minect), the cumulative is the only one locking the corresponding variable down, and the
9909  * objective coefficient of the start time variable is not negative, than removing the values {est+1,...,minect-1}
9910  * form variable domain is dual feasible.
9911  *
9912  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
9913  * the cumulative condition; The deletion has to be done later.
9914  */
9915 static
9917  SCIP* scip, /**< SCIP data structure */
9918  int nvars, /**< number of start time variables (activities) */
9919  SCIP_VAR** vars, /**< array of start time variables */
9920  int* durations, /**< array of durations */
9921  int hmin, /**< left bound of time axis to be considered (including hmin) */
9922  int hmax, /**< right bound of time axis to be considered (not including hmax) */
9923  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
9924  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
9925  SCIP_CONS* cons, /**< underlying constraint, or NULL */
9926  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
9927  int* nfixedvars, /**< pointer to store the number of fixed variables */
9928  int* nchgsides, /**< pointer to store the number of changed sides */
9929  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
9930  )
9931 {
9932  SCIP_Real* downimpllbs;
9933  SCIP_Real* downimplubs;
9934  SCIP_Real* downproplbs;
9935  SCIP_Real* downpropubs;
9936  SCIP_Real* upimpllbs;
9937  SCIP_Real* upimplubs;
9938  SCIP_Real* upproplbs;
9939  SCIP_Real* uppropubs;
9940 
9941  int firstminect;
9942  int secondminect;
9943  int v;
9944 
9945  /* get temporary memory for storing probing results needed for step (4) and (5) */
9946  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
9947  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
9948  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
9949  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
9950  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
9951  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
9952  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
9953  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
9954 
9955  assert(scip != NULL);
9956  assert(nvars > 1);
9957  assert(cons != NULL);
9958 
9959  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmin %d) w.r.t. earlier start time\n", hmin);
9960 
9961  firstminect = INT_MAX;
9962  secondminect = INT_MAX;
9963 
9964  /* compute the two smallest earlier completion times; which are needed for step (5) */
9965  for( v = 0; v < nvars; ++v )
9966  {
9967  int ect;
9968 
9969  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(vars[v])) + durations[v];
9970 
9971  if( ect < firstminect )
9972  {
9973  secondminect = firstminect;
9974  firstminect = ect;
9975  }
9976  else if( ect < secondminect )
9977  secondminect = ect;
9978  }
9979 
9980  /* loop over all jobs and check if one of the 5 reductions can be applied */
9981  for( v = 0; v < nvars; ++v )
9982  {
9983  SCIP_VAR* var;
9984  int duration;
9985 
9986  int alternativelb;
9987  int minect;
9988  int est;
9989  int ect;
9990  int lst;
9991  int lct;
9992 
9993  var = vars[v];
9994  assert(var != NULL);
9995 
9996  duration = durations[v];
9997  assert(duration > 0);
9998 
9999  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10000  * time (lct)
10001  */
10002  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10003  ect = est + duration;
10004  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10005  lct = lst + duration;
10006 
10007  /* compute the earliest completion time of all remaining jobs */
10008  if( ect == firstminect )
10009  minect = secondminect;
10010  else
10011  minect = firstminect;
10012 
10013  /* compute potential alternative lower bound (step (4) and (5)) */
10014  alternativelb = MAX(hmin+1, minect);
10015  alternativelb = MIN(alternativelb, hmax);
10016 
10017  if( lct <= hmin )
10018  {
10019  /* (1) check if the job runs completely before the effective horizon; if so the job can be removed form the
10020  * cumulative condition
10021  */
10022  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10023  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10024 
10025  /* mark variable to be irrelevant */
10026  irrelevants[v] = TRUE;
10027 
10028  /* for the statistic we count the number of jobs which are irrelevant */
10029  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10030  }
10031  else if( lst <= hmin && SCIPconsIsChecked(cons) )
10032  {
10033  /* (2) check if the jobs overlaps with the time point hmin if it overlaps at all with the effective horizon; if
10034  * so the down lock can be omitted
10035  */
10036 
10037  assert(downlocks != NULL);
10038  assert(uplocks != NULL);
10039 
10040  if( !uplocks[v] )
10041  {
10042  /* the variables has no up lock and we can also remove the down lock;
10043  * => lst <= hmin and ect >= hmax
10044  * => remove job and reduce capacity by the demand of that job
10045  *
10046  * We mark the job to be deletable. The removement together with the capacity reducion is done later
10047  */
10048 
10049  SCIPdebugMsg(scip, " variables <%s>[%d,%d] (duration <%d>) is irrelevant due to no up lock\n",
10050  SCIPvarGetName(var), ect - duration, lst, duration);
10051 
10052  /* mark variable to be irrelevant */
10053  irrelevants[v] = TRUE;
10054 
10055  /* for the statistic we count the number of jobs which always run during the effective horizon */
10057  }
10058 
10059  if( downlocks[v] )
10060  {
10061  SCIPdebugMsg(scip, " remove down lock of variable <%s>[%g,%g] with duration <%d>\n",
10062  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10063 
10064  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
10065  downlocks[v] = FALSE;
10066  (*nchgsides)++;
10067 
10068  /* for the statistic we count the number of removed locks */
10070  }
10071  }
10072  else if( ect <= hmin )
10073  {
10074  /* (3) check if the job can finish before the effective horizon starts; if so and the job can be fixed to its
10075  * earliest start time (which implies that it finishes before the effective horizon starts), the job can be
10076  * removed form the cumulative condition after it was fixed to its earliest start time
10077  */
10078 
10079  /* job can be removed from the constraint only if the integer start time variable can be fixed to its lower
10080  * bound;
10081  */
10082  if( downlocks != NULL && SCIPconsIsChecked(cons) )
10083  {
10084  /* fix integer start time variable if possible to it lower bound */
10085  SCIP_CALL( fixIntegerVariableLb(scip, var, downlocks[v], nfixedvars) );
10086  }
10087 
10088  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10089  {
10090  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt EST\n",
10091  SCIPvarGetName(var), ect - duration, lst, duration);
10092 
10093  /* after fixing the start time variable to its lower bound, the (new) earliest completion time should be smaller or equal ti hmin */
10094  assert(SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + duration <= hmin);
10095 
10096  /* mark variable to be irrelevant */
10097  irrelevants[v] = TRUE;
10098 
10099  /* for the statistic we count the number of jobs which are dual fixed */
10101  }
10102  }
10103  else if( est < lst && est < alternativelb && SCIPconsIsChecked(cons) )
10104  {
10105  assert(downlocks != NULL);
10106 
10107  /* check step (4) and (5) */
10108 
10109  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10110  * is in favor of rounding the variable down
10111  */
10112  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == (int)(downlocks[v]) )
10113  {
10114  SCIP_Bool roundable;
10115 
10116  SCIP_CALL( varMayRoundDown(scip, var, &roundable) );
10117 
10118  if( roundable )
10119  {
10120  if( alternativelb > lst )
10121  {
10122  SCIP_Bool infeasible;
10123  SCIP_Bool fixed;
10124 
10125  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetLbLocal(var), &infeasible, &fixed) );
10126  assert(!infeasible);
10127  assert(fixed);
10128 
10129  (*nfixedvars)++;
10130 
10131  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10132  * constraints
10133  */
10135  }
10136  else
10137  {
10138  SCIP_Bool success;
10139 
10140  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10141  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one in
10142  * infeasible we can apply the dual reduction; otherwise we do nothing
10143  */
10144  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) est, (SCIP_Real) alternativelb,
10145  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10146  nfixedvars, &success, cutoff) );
10147 
10148  if( success )
10149  {
10151  }
10152  }
10153  }
10154  }
10155  }
10156 
10157  SCIPdebugMsg(scip, "********* check variable <%s>[%g,%g] with duration <%d> (hmin %d)\n",
10158  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration, hmin);
10159  }
10160 
10161  /* free temporary memory */
10162  SCIPfreeBufferArray(scip, &uppropubs);
10163  SCIPfreeBufferArray(scip, &upproplbs);
10164  SCIPfreeBufferArray(scip, &upimplubs);
10165  SCIPfreeBufferArray(scip, &upimpllbs);
10166  SCIPfreeBufferArray(scip, &downpropubs);
10167  SCIPfreeBufferArray(scip, &downproplbs);
10168  SCIPfreeBufferArray(scip, &downimplubs);
10169  SCIPfreeBufferArray(scip, &downimpllbs);
10170 
10171  return SCIP_OKAY;
10172 }
10173 
10174 /** presolve cumulative condition w.r.t. the latest completion times (lct) and the hmax of the effective horizon
10175  *
10176  * (1) If the earliest start time (est) of a job is larger or equal than hmax, the corresponding job can be removed
10177  * form the constraint. This is the case since it cannot effect any assignment within the effective horizon
10178  *
10179  * (2) If the earliest completion time (ect) of a job is larger or equal than hmax it follows that the this jobs can run
10180  * before the effective horizon or it overlaps with the effective horizon such that hmax in included. Hence, the
10181  * up-lock of the corresponding start time variable can be removed.
10182  *
10183  * (3) If the latest start time (lst) of a job is larger or equal than hmax, the cumulative is the only one
10184  * locking the corresponding variable up, and the objective coefficient of the start time variable is not
10185  * positive, than the job can be dual fixed to its latest start time (lst).
10186  *
10187  * (4) If the latest completion time (lct) of job is larger than the hmax, the cumulative is the only one locking the
10188  * corresponding variable up, and the objective coefficient of the start time variable is not positive, than
10189  * removing the values {hmax - p_j, ..., lst-1} form variable domain is dual feasible (p_j is the processing time
10190  * of the corresponding job).
10191 
10192  * (5) If the latest completion time (lct) of job is smaller than the largerst latest start time of all other jobs
10193  * (lets denote this with maxlst), the cumulative is the only one locking the corresponding variable up, and the
10194  * objective coefficient of the start time variable is not positive, than removing the values {maxlst - p_j + 1,
10195  * ..., lst-1} form variable domain is dual feasible (p_j is the processing time of the corresponding job).
10196  *
10197  * @note That method does not remove any variable form the arrays. It only marks the variables which are irrelevant for
10198  * the cumulative condition; The deletion has to be done later.
10199  */
10200 static
10202  SCIP* scip, /**< SCIP data structure */
10203  int nvars, /**< number of start time variables (activities) */
10204  SCIP_VAR** vars, /**< array of start time variables */
10205  int* durations, /**< array of durations */
10206  int hmin, /**< left bound of time axis to be considered (including hmin) */
10207  int hmax, /**< right bound of time axis to be considered (not including hmax) */
10208  SCIP_Bool* downlocks, /**< array to store if the variable has a down lock, or NULL */
10209  SCIP_Bool* uplocks, /**< array to store if the variable has an up lock, or NULL */
10210  SCIP_CONS* cons, /**< underlying constraint, or NULL */
10211  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
10212  int* nfixedvars, /**< pointer to counter which is increased by the number of deduced variable fixations */
10213  int* nchgsides, /**< pointer to store the number of changed sides */
10214  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
10215  )
10216 {
10217  SCIP_Real* downimpllbs;
10218  SCIP_Real* downimplubs;
10219  SCIP_Real* downproplbs;
10220  SCIP_Real* downpropubs;
10221  SCIP_Real* upimpllbs;
10222  SCIP_Real* upimplubs;
10223  SCIP_Real* upproplbs;
10224  SCIP_Real* uppropubs;
10225 
10226  int firstmaxlst;
10227  int secondmaxlst;
10228  int v;
10229 
10230  /* get temporary memory for storing probing results needed for step (4) and (5) */
10231  SCIP_CALL( SCIPallocBufferArray(scip, &downimpllbs, nvars) );
10232  SCIP_CALL( SCIPallocBufferArray(scip, &downimplubs, nvars) );
10233  SCIP_CALL( SCIPallocBufferArray(scip, &downproplbs, nvars) );
10234  SCIP_CALL( SCIPallocBufferArray(scip, &downpropubs, nvars) );
10235  SCIP_CALL( SCIPallocBufferArray(scip, &upimpllbs, nvars) );
10236  SCIP_CALL( SCIPallocBufferArray(scip, &upimplubs, nvars) );
10237  SCIP_CALL( SCIPallocBufferArray(scip, &upproplbs, nvars) );
10238  SCIP_CALL( SCIPallocBufferArray(scip, &uppropubs, nvars) );
10239 
10240  assert(scip != NULL);
10241  assert(nvars > 1);
10242  assert(cons != NULL);
10243 
10244  SCIPdebugMsg(scip, "check for irrelevant variable for cumulative condition (hmax %d) w.r.t. latest completion time\n", hmax);
10245 
10246  firstmaxlst = INT_MIN;
10247  secondmaxlst = INT_MIN;
10248 
10249  /* compute the two largest latest start times; which are needed for step (5) */
10250  for( v = 0; v < nvars; ++v )
10251  {
10252  int lst;
10253 
10254  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(vars[v]));
10255 
10256  if( lst > firstmaxlst )
10257  {
10258  secondmaxlst = firstmaxlst;
10259  firstmaxlst = lst;
10260  }
10261  else if( lst > secondmaxlst )
10262  secondmaxlst = lst;
10263  }
10264 
10265  /* loop over all jobs and check if one of the 5 reductions can be applied */
10266  for( v = 0; v < nvars; ++v )
10267  {
10268  SCIP_VAR* var;
10269  int duration;
10270 
10271  int alternativeub;
10272  int maxlst;
10273  int est;
10274  int ect;
10275  int lst;
10276 
10277  var = vars[v];
10278  assert(var != NULL);
10279 
10280  duration = durations[v];
10281  assert(duration > 0);
10282 
10283  /* collect earlier start time (est), earlier completion time (ect), latest start time (lst), and latest completion
10284  * time (lct)
10285  */
10286  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10287  ect = est + duration;
10288  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10289 
10290  /* compute the latest start time of all remaining jobs */
10291  if( lst == firstmaxlst )
10292  maxlst = secondmaxlst;
10293  else
10294  maxlst = firstmaxlst;
10295 
10296  /* compute potential alternative upper bound (step (4) and (5)) */
10297  alternativeub = MIN(hmax - 1, maxlst) - duration;
10298  alternativeub = MAX(alternativeub, hmin);
10299 
10300  if( est >= hmax )
10301  {
10302  /* (1) check if the job runs completely after the effective horizon; if so the job can be removed form the
10303  * cumulative condition
10304  */
10305  SCIPdebugMsg(scip, " variable <%s>[%g,%g] with duration <%d> is irrelevant\n",
10306  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10307 
10308  /* mark variable to be irrelevant */
10309  irrelevants[v] = TRUE;
10310 
10311  /* for the statistic we count the number of jobs which are irrelevant */
10312  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->nirrelevantjobs++ );
10313  }
10314  else if( ect >= hmax && SCIPconsIsChecked(cons) )
10315  {
10316  assert(downlocks != NULL);
10317  assert(uplocks != NULL);
10318 
10319  /* (2) check if the jobs overlaps with the time point hmax if it overlaps at all with the effective horizon; if
10320  * so the up lock can be omitted
10321  */
10322 
10323  if( !downlocks[v] )
10324  {
10325  /* the variables has no down lock and we can also remove the up lock;
10326  * => lst <= hmin and ect >= hmax
10327  * => remove job and reduce capacity by the demand of that job
10328  */
10329  SCIPdebugMsg(scip, " variables <%s>[%d,%d] with duration <%d> is irrelevant due to no down lock\n",
10330  SCIPvarGetName(var), est, lst, duration);
10331 
10332  /* mark variable to be irrelevant */
10333  irrelevants[v] = TRUE;
10334 
10335  /* for the statistic we count the number of jobs which always run during the effective horizon */
10337  }
10338 
10339  if( uplocks[v] )
10340  {
10341  SCIPdebugMsg(scip, " remove up lock of variable <%s>[%g,%g] with duration <%d>\n",
10342  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), duration);
10343 
10344  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
10345  uplocks[v] = FALSE;
10346  (*nchgsides)++;
10347 
10348  /* for the statistic we count the number of removed locks */
10350  }
10351  }
10352  else if( lst >= hmax )
10353  {
10354  /* (3) check if the job can start after the effective horizon finishes; if so and the job can be fixed to its
10355  * latest start time (which implies that it starts after the effective horizon finishes), the job can be
10356  * removed form the cumulative condition after it was fixed to its latest start time
10357  */
10358 
10359  /* job can be removed from the constraint only if the integer start time variable can be fixed to its upper
10360  * bound
10361  */
10362  if( uplocks != NULL && SCIPconsIsChecked(cons) )
10363  {
10364  /* fix integer start time variable if possible to its upper bound */
10365  SCIP_CALL( fixIntegerVariableUb(scip, var, uplocks[v], nfixedvars) );
10366  }
10367 
10368  if( SCIPvarGetLbGlobal(var) + 0.5 > SCIPvarGetUbGlobal(var) )
10369  {
10370  SCIPdebugMsg(scip, " variable <%s>[%d,%d] with duration <%d> is irrelevant due to dual fixing wrt LCT\n",
10371  SCIPvarGetName(var), est, lst, duration);
10372 
10373  /* after fixing the start time variable to its upper bound, the (new) latest start time should be greather or equal ti hmax */
10374  assert(SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) >= hmax);
10375 
10376  /* mark variable to be irrelevant */
10377  irrelevants[v] = TRUE;
10378 
10379  /* for the statistic we count the number of jobs which are dual fixed */
10381  }
10382  }
10383  else if( est < lst && lst > alternativeub && SCIPconsIsChecked(cons) )
10384  {
10385  assert(uplocks != NULL);
10386 
10387  /* check step (4) and (5) */
10388 
10389  /* check if the cumulative constraint is the only one looking this variable down and if the objective function
10390  * is in favor of rounding the variable down
10391  */
10392  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == (int)(uplocks[v]) )
10393  {
10394  SCIP_Bool roundable;
10395 
10396  SCIP_CALL( varMayRoundUp(scip, var, &roundable) );
10397 
10398  if( roundable )
10399  {
10400  if( alternativeub < est )
10401  {
10402  SCIP_Bool infeasible;
10403  SCIP_Bool fixed;
10404 
10405  SCIP_CALL( SCIPfixVar(scip, var, SCIPvarGetUbLocal(var), &infeasible, &fixed) );
10406  assert(!infeasible);
10407  assert(fixed);
10408 
10409  (*nfixedvars)++;
10410 
10411  /* for the statistic we count the number of jobs which are dual fixed due the information of all cumulative
10412  * constraints
10413  */
10415  }
10416  else
10417  {
10418  SCIP_Bool success;
10419 
10420  /* In the current version SCIP, variable domains are single intervals. Meaning that domain holes or not
10421  * representable. To retrieve a potential dual reduction we using probing to check both branches. If one
10422  * in infeasible we can apply the dual reduction; otherwise we do nothing
10423  */
10424  SCIP_CALL( applyProbingVar(scip, vars, nvars, v, (SCIP_Real) alternativeub, (SCIP_Real) lst,
10425  downimpllbs, downimplubs, downproplbs, downpropubs, upimpllbs, upimplubs, upproplbs, uppropubs,
10426  nfixedvars, &success, cutoff) );
10427 
10428  if( success )
10429  {
10431  }
10432  }
10433  }
10434  }
10435  }
10436  }
10437 
10438  /* free temporary memory */
10439  SCIPfreeBufferArray(scip, &uppropubs);
10440  SCIPfreeBufferArray(scip, &upproplbs);
10441  SCIPfreeBufferArray(scip, &upimplubs);
10442  SCIPfreeBufferArray(scip, &upimpllbs);
10443  SCIPfreeBufferArray(scip, &downpropubs);
10444  SCIPfreeBufferArray(scip, &downproplbs);
10445  SCIPfreeBufferArray(scip, &downimplubs);
10446  SCIPfreeBufferArray(scip, &downimpllbs);
10447 
10448  return SCIP_OKAY;
10449 }
10450 
10451 /** presolve cumulative constraint w.r.t. the boundary of the effective horizon */
10452 static
10454  SCIP* scip, /**< SCIP data structure */
10455  SCIP_CONS* cons, /**< cumulative constraint */
10456  int* nfixedvars, /**< pointer to store the number of fixed variables */
10457  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
10458  int* nchgsides, /**< pointer to store the number of changed sides */
10459  SCIP_Bool* cutoff /**< pointer to store if a cutoff was detected */
10460  )
10461 {
10462  SCIP_CONSDATA* consdata;
10463  SCIP_Bool* irrelevants;
10464  int nvars;
10465  int v;
10466 
10467  assert(scip != NULL);
10468  assert(cons != NULL);
10469  assert(!(*cutoff));
10470 
10471  consdata = SCIPconsGetData(cons);
10472  assert(consdata != NULL);
10473 
10474  nvars = consdata->nvars;
10475 
10476  if( nvars <= 1 )
10477  return SCIP_OKAY;
10478 
10479  SCIP_CALL( SCIPallocBufferArray(scip, &irrelevants, nvars) );
10480  BMSclearMemoryArray(irrelevants, nvars);
10481 
10482  /* presolve constraint form the earlier start time point of view */
10483  SCIP_CALL( presolveConsEst(scip, nvars, consdata->vars, consdata->durations,
10484  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10485  irrelevants, nfixedvars, nchgsides, cutoff) );
10486 
10487  /* presolve constraint form the latest completion time point of view */
10488  SCIP_CALL( presolveConsLct(scip, nvars, consdata->vars, consdata->durations,
10489  consdata->hmin, consdata->hmax, consdata->downlocks, consdata->uplocks, cons,
10490  irrelevants, nfixedvars, nchgsides, cutoff) );
10491 
10492  /* remove variables from the cumulative constraint which are marked to be deleted; we need to that in the reverse
10493  * order to ensure a correct behaviour
10494  */
10495  for( v = nvars-1; v >= 0; --v )
10496  {
10497  if( irrelevants[v] )
10498  {
10499  SCIP_VAR* var;
10500  int ect;
10501  int lst;
10502 
10503  var = consdata->vars[v];
10504  assert(var != NULL);
10505 
10506  ect = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var)) + consdata->durations[v];
10507  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10508 
10509  /* check if the jobs runs completely during the effective horizon */
10510  if( lst <= consdata->hmin && ect >= consdata->hmax )
10511  {
10512  if( consdata->capacity < consdata->demands[v] )
10513  {
10514  *cutoff = TRUE;
10515  break;
10516  }
10517 
10518  consdata->capacity -= consdata->demands[v];
10519  consdata->varbounds = FALSE;
10520  }
10521 
10522  SCIP_CALL( consdataDeletePos(scip, consdata, cons, v) );
10523  (*nchgcoefs)++;
10524  }
10525  }
10526 
10527  SCIPfreeBufferArray(scip, &irrelevants);
10528 
10529  return SCIP_OKAY;
10530 }
10531 
10532 /** stores all demands which are smaller than the capacity of those jobs that are running at 'curtime' */
10533 static
10534 void collectDemands(
10535  SCIP* scip, /**< SCIP data structure */
10536  SCIP_CONSDATA* consdata, /**< constraint data */
10537  int* startindices, /**< permutation with rspect to the start times */
10538  int curtime, /**< current point in time */
10539  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10540  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10541  SCIP_Longint** demands, /**< pointer to array storing the demands */
10542  int* ndemands /**< pointer to store the number of different demands */
10543  )
10544 {
10545  int startindex;
10546  int ncountedvars;
10547 
10548  assert(demands != NULL);
10549  assert(ndemands != NULL);
10550 
10551  ncountedvars = 0;
10552  startindex = nstarted - 1;
10553 
10554  *ndemands = 0;
10555 
10556  /* search for the (nstarted - nfinished) jobs which are active at curtime */
10557  while( nstarted - nfinished > ncountedvars )
10558  {
10559  SCIP_VAR* var;
10560  int endtime;
10561  int varidx;
10562 
10563  /* collect job information */
10564  varidx = startindices[startindex];
10565  assert(varidx >= 0 && varidx < consdata->nvars);
10566 
10567  var = consdata->vars[varidx];
10568  assert(var != NULL);
10569 
10570  endtime = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var)) + consdata->durations[varidx];
10571 
10572  /* check the end time of this job is larger than the curtime; in this case the job is still running */
10573  if( endtime > curtime )
10574  {
10575  if( consdata->demands[varidx] < consdata->capacity )
10576  {
10577  (*demands)[*ndemands] = consdata->demands[varidx];
10578  (*ndemands)++;
10579  }
10580  ncountedvars++;
10581  }
10582 
10583  startindex--;
10584  }
10585 }
10586 
10587 /** this method creates a row for time point curtime which insures the capacity restriction of the cumulative
10588  * constraint
10589  */
10590 static
10592  SCIP* scip, /**< SCIP data structure */
10593  SCIP_CONS* cons, /**< constraint to be checked */
10594  int* startindices, /**< permutation with rspect to the start times */
10595  int curtime, /**< current point in time */
10596  int nstarted, /**< number of jobs that start before the curtime or at curtime */
10597  int nfinished, /**< number of jobs that finished before curtime or at curtime */
10598  int* bestcapacity /**< pointer to store the maximum possible capacity usage */
10599  )
10600 {
10601  SCIP_CONSDATA* consdata;
10602  SCIP_Longint* demands;
10603  SCIP_Real* profits;
10604  int* items;
10605  int ndemands;
10606  SCIP_Bool success;
10607  SCIP_Real solval;
10608  int j;
10609  assert(nstarted > nfinished);
10610 
10611  consdata = SCIPconsGetData(cons);
10612  assert(consdata != NULL);
10613  assert(consdata->nvars > 0);
10614  assert(consdata->capacity > 0);
10615 
10616  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
10617  ndemands = 0;
10618 
10619  /* get demand array to initialize knapsack problem */
10620  collectDemands(scip, consdata, startindices, curtime, nstarted, nfinished, &demands, &ndemands);
10621 
10622  /* create array for profits */
10623  SCIP_CALL( SCIPallocBufferArray(scip, &profits, ndemands) );
10624  SCIP_CALL( SCIPallocBufferArray(scip, &items, ndemands) );
10625  for( j = 0; j < ndemands; ++j )
10626  {
10627  profits[j] = (SCIP_Real) demands[j];
10628  items[j] = j;/* this is only a dummy value*/
10629  }
10630 
10631  /* solve knapsack problem and get maximum capacity usage <= capacity */
10632  SCIP_CALL( SCIPsolveKnapsackExactly(scip, ndemands, demands, profits, (SCIP_Longint)consdata->capacity,
10633  items, NULL, NULL, NULL, NULL, &solval, &success) );
10634 
10635  assert(SCIPisFeasIntegral(scip, solval));
10636 
10637  /* store result */
10638  *bestcapacity = SCIPconvertRealToInt(scip, solval);
10639 
10640  SCIPfreeBufferArray(scip, &items);
10641  SCIPfreeBufferArray(scip, &profits);
10642  SCIPfreeBufferArray(scip, &demands);
10643 
10644  return SCIP_OKAY;
10645 }
10646 
10647 /** try to tighten the capacity
10648  * -- using DP for knapsack, we find the maximum possible capacity usage
10649  * -- neglects hmin and hmax, such that it is also able to check solutions globally
10650  */
10651 static
10653  SCIP* scip, /**< SCIP data structure */
10654  SCIP_CONS* cons, /**< cumulative constraint */
10655  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
10656  int* nchgsides /**< pointer to store the number of changed sides */
10657  )
10658 {
10659  SCIP_CONSDATA* consdata;
10660  int* starttimes; /* stores when each job is starting */
10661  int* endtimes; /* stores when each job ends */
10662  int* startindices; /* we will sort the startsolvalues, thus we need to know wich index of a job it corresponds to */
10663  int* endindices; /* we will sort the endsolvalues, thus we need to know wich index of a job it corresponds to */
10664 
10665  int nvars; /* number of activities for this constraint */
10666  int freecapacity; /* remaining capacity */
10667  int curtime; /* point in time which we are just checking */
10668  int endindex; /* index of endsolvalues with: endsolvalues[endindex] > curtime */
10669 
10670  int bestcapacity;
10671 
10672  int j;
10673 
10674  assert(scip != NULL);
10675  assert(cons != NULL);
10676  assert(nchgsides != NULL);
10677 
10678  consdata = SCIPconsGetData(cons);
10679  assert(consdata != NULL);
10680 
10681  nvars = consdata->nvars;
10682 
10683  /* if no activities are associated with this cumulative or the capacity is 1, then this constraint is redundant */
10684  if( nvars <= 1 || consdata->capacity <= 1 )
10685  return SCIP_OKAY;
10686 
10687  assert(consdata->vars != NULL);
10688 
10689  SCIPdebugMsg(scip, "try to tighten capacity for cumulative constraint <%s> with capacity %d\n",
10690  SCIPconsGetName(cons), consdata->capacity);
10691 
10692  SCIP_CALL( SCIPallocBufferArray(scip, &starttimes, nvars) );
10693  SCIP_CALL( SCIPallocBufferArray(scip, &endtimes, nvars) );
10694  SCIP_CALL( SCIPallocBufferArray(scip, &startindices, nvars) );
10695  SCIP_CALL( SCIPallocBufferArray(scip, &endindices, nvars) );
10696 
10697  /* create event point arrays */
10698  createSortedEventpoints(scip, nvars, consdata->vars, consdata->durations,
10699  starttimes, endtimes, startindices, endindices, FALSE);
10700 
10701  bestcapacity = 1;
10702  endindex = 0;
10703  freecapacity = consdata->capacity;
10704 
10705  /* check each startpoint of a job whether the capacity is kept or not */
10706  for( j = 0; j < nvars && bestcapacity < consdata->capacity; ++j )
10707  {
10708  curtime = starttimes[j];
10709  SCIPdebugMsg(scip, "look at %d-th job with start %d\n", j, curtime);
10710 
10711  /* remove the capacity requirments for all job which start at the curtime */
10712  subtractStartingJobDemands(consdata, curtime, starttimes, startindices, &freecapacity, &j, nvars);
10713 
10714  /* add the capacity requirments for all job which end at the curtime */
10715  addEndingJobDemands(consdata, curtime, endtimes, endindices, &freecapacity, &endindex, nvars);
10716 
10717  assert(freecapacity <= consdata->capacity);
10718  assert(endindex <= nvars);
10719 
10720  /* endindex - points to the next job which will finish */
10721  /* j - points to the last job that has been released */
10722 
10723  /* check point in time when capacity is exceeded (here, a knapsack problem must be solved) */
10724  if( freecapacity < 0 )
10725  {
10726  int newcapacity;
10727 
10728  newcapacity = 1;
10729 
10730  /* get best possible upper bound on capacity usage */
10731  SCIP_CALL( getHighestCapacityUsage(scip, cons, startindices, curtime, j+1, endindex, &newcapacity) );
10732 
10733  /* update bestcapacity */
10734  bestcapacity = MAX(bestcapacity, newcapacity);
10735  SCIPdebugMsg(scip, "after highest cap usage: bestcapacity = %d\n", bestcapacity);
10736  }
10737 
10738  /* also those points in time, where the capacity limit is not exceeded, must be taken into account */
10739  if( freecapacity > 0 && freecapacity != consdata->capacity )
10740  {
10741  bestcapacity = MAX(bestcapacity, consdata->capacity - freecapacity);
10742  SCIPdebugMsg(scip, "after peak < cap: bestcapacity = %d\n", bestcapacity);
10743  }
10744 
10745  /* capacity cannot be decreased if the demand sum over more than one job equals the capacity */
10746  if( freecapacity == 0 && consdata->demands[startindices[j]] < consdata->capacity)
10747  {
10748  /* if demands[startindices[j]] == cap then exactly that job is running */
10749  SCIPdebugMsg(scip, "--> cannot decrease capacity since sum equals capacity\n");
10750  bestcapacity = consdata->capacity;
10751  break;
10752  }
10753  } /*lint --e{850}*/
10754 
10755  /* free all buffer arrays */
10756  SCIPfreeBufferArray(scip, &endindices);
10757  SCIPfreeBufferArray(scip, &startindices);
10758  SCIPfreeBufferArray(scip, &endtimes);
10759  SCIPfreeBufferArray(scip, &starttimes);
10760 
10761  /* check whether capacity can be tightened and whether demands need to be adjusted */
10762  if( bestcapacity < consdata->capacity )
10763  {
10764  SCIPdebug( int oldnchgcoefs = *nchgcoefs; )
10765 
10766  SCIPdebugMsg(scip, "+-+-+-+-+-+ --> CHANGE capacity of cons<%s> from %d to %d\n",
10767  SCIPconsGetName(cons), consdata->capacity, bestcapacity);
10768 
10769  for( j = 0; j < nvars; ++j )
10770  {
10771  if( consdata->demands[j] == consdata->capacity )
10772  {
10773  consdata->demands[j] = bestcapacity;
10774  (*nchgcoefs)++;
10775  }
10776  }
10777 
10778  consdata->capacity = bestcapacity;
10779  (*nchgsides)++;
10780 
10781  SCIPdebug( SCIPdebugMsg(scip, "; changed additionally %d coefficients\n", (*nchgcoefs) - oldnchgcoefs); )
10782 
10783  consdata->varbounds = FALSE;
10784  }
10785 
10786  return SCIP_OKAY;
10787 }
10788 
10789 /** tries to change coefficients:
10790  * demand_j < cap && all other parallel jobs in conflict
10791  * ==> set demand_j := cap
10792  */
10793 static
10795  SCIP* scip, /**< SCIP data structure */
10796  SCIP_CONS* cons, /**< cumulative constraint */
10797  int* nchgcoefs /**< pointer to count total number of changed coefficients */
10798  )
10799 {
10800  SCIP_CONSDATA* consdata;
10801  int nvars;
10802  int j;
10803  int oldnchgcoefs;
10804  int mindemand;
10805 
10806  assert(scip != NULL);
10807  assert(cons != NULL);
10808  assert(nchgcoefs != NULL);
10809 
10810  /* get constraint data for some parameter testings only! */
10811  consdata = SCIPconsGetData(cons);
10812  assert(consdata != NULL);
10813 
10814  nvars = consdata->nvars;
10815  oldnchgcoefs = *nchgcoefs;
10816 
10817  if( nvars <= 0 )
10818  return SCIP_OKAY;
10819 
10820  /* PRE1:
10821  * check all jobs j whether: r_j + r_min > capacity holds
10822  * if so: adjust r_j to capacity
10823  */
10824  mindemand = consdata->demands[0];
10825  for( j = 0; j < nvars; ++j )
10826  {
10827  mindemand = MIN(mindemand, consdata->demands[j]);
10828  }
10829 
10830  /*check each job */
10831  for( j = 0; j < nvars; ++j )
10832  {
10833  if( mindemand + consdata->demands[j] > consdata->capacity && consdata->demands[j] < consdata->capacity )
10834  {
10835  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10836  consdata->demands[j], consdata->capacity);
10837  consdata->demands[j] = consdata->capacity;
10838  (*nchgcoefs)++;
10839  }
10840  }
10841 
10842  /* PRE2:
10843  * check for each job (with d_j < cap)
10844  * whether it is disjunctive to all others over the time horizon
10845  */
10846  for( j = 0; j < nvars; ++j )
10847  {
10848  SCIP_Bool chgcoef;
10849  int est_j;
10850  int lct_j;
10851  int i;
10852 
10853  assert(consdata->demands[j] <= consdata->capacity);
10854 
10855  if( consdata->demands[j] == consdata->capacity )
10856  continue;
10857 
10858  chgcoef = TRUE;
10859 
10860  est_j = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[j]));
10861  lct_j = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[j])) + consdata->durations[j];
10862 
10863  for( i = 0; i < nvars; ++i )
10864  {
10865  int est_i;
10866  int lct_i;
10867 
10868  if( i == j )
10869  continue;
10870 
10871  est_i = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(consdata->vars[i]));
10872  lct_i = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(consdata->vars[i])) + consdata->durations[i];
10873 
10874  if( est_i >= lct_j || est_j >= lct_i )
10875  continue;
10876 
10877  if( consdata->demands[j] + consdata->demands[i] <= consdata->capacity )
10878  {
10879  chgcoef = FALSE;
10880  break;
10881  }
10882  }
10883 
10884  if( chgcoef )
10885  {
10886  SCIPdebugMsg(scip, "+-+-+-+-+-+change demand of var<%s> from %d to capacity %d\n", SCIPvarGetName(consdata->vars[j]),
10887  consdata->demands[j], consdata->capacity);
10888  consdata->demands[j] = consdata->capacity;
10889  (*nchgcoefs)++;
10890  }
10891  }
10892 
10893  if( (*nchgcoefs) > oldnchgcoefs )
10894  {
10895  SCIPdebugMsg(scip, "+-+-+-+-+-+changed %d coefficients of variables of cumulative constraint<%s>\n",
10896  (*nchgcoefs) - oldnchgcoefs, SCIPconsGetName(cons));
10897  }
10898 
10899  return SCIP_OKAY;
10900 }
10901 
10902 #if 0
10903 /** try to reformulate constraint by replacing certain jobs */
10904 static
10905 SCIP_RETCODE reformulateCons(
10906  SCIP* scip, /**< SCIP data structure */
10907  SCIP_CONS* cons, /**< cumulative constraint */
10908  int* naggrvars /**< pointer to store the number of aggregated variables */
10909  )
10910 {
10911  SCIP_CONSDATA* consdata;
10912  int hmin;
10913  int hmax;
10914  int nvars;
10915  int v;
10916 
10917  consdata = SCIPconsGetData(cons);
10918  assert(cons != NULL);
10919 
10920  nvars = consdata->nvars;
10921  assert(nvars > 1);
10922 
10923  hmin = consdata->hmin;
10924  hmax = consdata->hmax;
10925  assert(hmin < hmax);
10926 
10927  for( v = 0; v < nvars; ++v )
10928  {
10929  SCIP_VAR* var;
10930  int duration;
10931  int est;
10932  int ect;
10933  int lst;
10934  int lct;
10935 
10936  var = consdata->vars[v];
10937  assert(var != NULL);
10938 
10939  duration = consdata->durations[v];
10940 
10941  est = SCIPconvertRealToInt(scip, SCIPvarGetLbGlobal(var));
10942  ect = est + duration;
10943  lst = SCIPconvertRealToInt(scip, SCIPvarGetUbGlobal(var));
10944  lct = lst + duration;
10945 
10946  /* jobs for which the core [lst,ect) contains [hmin,hmax) should be removed already */
10947  assert(lst > hmin || ect < hmax);
10948 
10949  if( lst <= hmin && est < hmin - lct + MIN(hmin, ect) )
10950  {
10951  SCIP_VAR* aggrvar;
10952  char name[SCIP_MAXSTRLEN];
10953  SCIP_Bool infeasible;
10954  SCIP_Bool redundant;
10955  SCIP_Bool aggregated;
10956  int shift;
10957 
10958  shift = est - (hmin - lct + MIN(hmin, ect));
10959  assert(shift > 0);
10960  lst = hmin;
10961  duration = hmin - lct;
10962 
10963  SCIPdebugMsg(scip, "replace variable <%s>[%g,%g] by [%d,%d]\n",
10964  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), est + shift, lst);
10965 
10966  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_aggr", SCIPvarGetName(var));
10967  SCIP_CALL( SCIPcreateVar(scip, &aggrvar, name, (SCIP_Real)(est+shift), (SCIP_Real)lst, 0.0, SCIPvarGetType(var),
10969  SCIP_CALL( SCIPaddVar(scip, var) );
10970  SCIP_CALL( SCIPaggregateVars(scip, var, aggrvar, 1.0, -1.0, (SCIP_Real)shift, &infeasible, &redundant, &aggregated) );
10971 
10972  assert(!infeasible);
10973  assert(!redundant);
10974  assert(aggregated);
10975 
10976  /* replace variable */
10977  consdata->durations[v] = duration;
10978  consdata->vars[v] = aggrvar;
10979 
10980  /* remove and add locks */
10981  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10982  SCIP_CALL( SCIPlockVarCons(scip, var, cons, consdata->downlocks[v], consdata->uplocks[v]) );
10983 
10984  SCIP_CALL( SCIPreleaseVar(scip, &aggrvar) );
10985 
10986  (*naggrvars)++;
10987  }
10988  }
10989 
10990  return SCIP_OKAY;
10991 }
10992 #endif
10993 
10994 /** creare a disjunctive constraint which contains all jobs which cannot run in parallel */
10995 static
10997  SCIP* scip, /**< SCIP data structure */
10998  SCIP_CONS* cons, /**< cumulative constraint */
10999  int* naddconss /**< pointer to store the number of added constraints */
11000  )
11001 {
11002  SCIP_CONSDATA* consdata;
11003  SCIP_VAR** vars;
11004  int* durations;
11005  int* demands;
11006  int capacity;
11007  int halfcapacity;
11008  int mindemand;
11009  int nvars;
11010  int v;
11011 
11012  consdata = SCIPconsGetData(cons);
11013  assert(consdata != NULL);
11014 
11015  capacity = consdata->capacity;
11016 
11017  if( capacity == 1 )
11018  return SCIP_OKAY;
11019 
11020  SCIP_CALL( SCIPallocBufferArray(scip, &vars, consdata->nvars) );
11021  SCIP_CALL( SCIPallocBufferArray(scip, &durations, consdata->nvars) );
11022  SCIP_CALL( SCIPallocBufferArray(scip, &demands, consdata->nvars) );
11023 
11024  halfcapacity = capacity / 2;
11025  mindemand = consdata->capacity;
11026  nvars = 0;
11027 
11028  /* collect all jobs with demand larger than half of the capacity */
11029  for( v = 0; v < consdata->nvars; ++v )
11030  {
11031  if( consdata->demands[v] > halfcapacity )
11032  {
11033  vars[nvars] = consdata->vars[v];
11034  demands[nvars] = 1;
11035  durations[nvars] = consdata->durations[v];
11036  nvars++;
11037 
11038  mindemand = MIN(mindemand, consdata->demands[v]);
11039  }
11040  }
11041 
11042  if( nvars > 0 )
11043  {
11044  /* add all jobs which has a demand smaller than one half of the capacity but together with the smallest collected
11045  * job is still to large to be scheduled in parallel
11046  */
11047  for( v = 0; v < consdata->nvars; ++v )
11048  {
11049  if( consdata->demands[v] > halfcapacity )
11050  continue;
11051 
11052  if( mindemand + consdata->demands[v] > capacity )
11053  {
11054  demands[nvars] = 1;
11055  durations[nvars] = consdata->durations[v];
11056  vars[nvars] = consdata->vars[v];
11057  nvars++;
11058 
11059  /* @todo create one cumulative constraint and look for another small demand */
11060  break;
11061  }
11062  }
11063 
11064  /* creates cumulative constraint and adds it to problem */
11065  SCIP_CALL( createConsCumulative(scip, SCIPconsGetName(cons), nvars, vars, durations, demands, 1, consdata->hmin, consdata->hmax,
11067  (*naddconss)++;
11068  }
11069 
11070  SCIPfreeBufferArray(scip, &demands);
11071  SCIPfreeBufferArray(scip, &durations);
11072  SCIPfreeBufferArray(scip, &vars);
11073 
11074  return SCIP_OKAY;
11075 }
11076 
11077 /** presolve given constraint */
11078 static
11080  SCIP* scip, /**< SCIP data structure */
11081  SCIP_CONS* cons, /**< cumulative constraint */
11082  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
11083  SCIP_PRESOLTIMING presoltiming, /**< timing of presolving call */
11084  int* nfixedvars, /**< pointer to store the number of fixed variables */
11085 #if 0
11086  int* naggrvars, /**< pointer to counter which is increased by the number of deduced variable aggregations */
11087 #endif
11088  int* nchgbds, /**< pointer to store the number of changed bounds */
11089  int* ndelconss, /**< pointer to store the number of deleted constraints */
11090  int* naddconss, /**< pointer to store the number of added constraints */
11091  int* nchgcoefs, /**< pointer to store the number of changed coefficients */
11092  int* nchgsides, /**< pointer to store the number of changed sides */
11093  SCIP_Bool* cutoff, /**< pointer to store if a cutoff was detected */
11094  SCIP_Bool* unbounded /**< pointer to store if the problem is unbounded */
11095  )
11096 {
11097  assert(!SCIPconsIsDeleted(cons));
11098 
11099  /* only perform dual reductions on model constraints */
11100  if( conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) )
11101  {
11102  /* computes the effective horizon and checks if the constraint can be decomposed */
11103  SCIP_CALL( computeEffectiveHorizon(scip, cons, ndelconss, naddconss, nchgsides) );
11104 
11105  if( SCIPconsIsDeleted(cons) )
11106  return SCIP_OKAY;
11107 
11108  /* in case the cumulative constraint is independent of every else, solve the cumulative problem and apply the
11109  * fixings (dual reductions)
11110  */
11111  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
11112  {
11113  SCIP_CALL( solveIndependentCons(scip, cons, conshdlrdata->maxnodes, nchgbds, nfixedvars, ndelconss, cutoff, unbounded) );
11114 
11115  if( *cutoff || *unbounded || presoltiming == SCIP_PRESOLTIMING_EXHAUSTIVE )
11116  return SCIP_OKAY;
11117  }
11118 
11119  SCIP_CALL( presolveConsEffectiveHorizon(scip, cons, nfixedvars, nchgcoefs, nchgsides, cutoff) );
11120 
11121  if( *cutoff || SCIPconsIsDeleted(cons) )
11122  return SCIP_OKAY;
11123  }
11124 
11125  /* remove jobs which have a demand larger than the capacity */
11126  SCIP_CALL( removeOversizedJobs(scip, cons, nchgbds, nchgcoefs, naddconss, cutoff) );
11127  assert((*cutoff) || checkDemands(scip, cons));
11128 
11129  if( *cutoff )
11130  return SCIP_OKAY;
11131 
11132  if( conshdlrdata->normalize )
11133  {
11134  /* divide demands by their greatest common divisor */
11135  normalizeDemands(scip, cons, nchgcoefs, nchgsides);
11136  }
11137 
11138  /* delete constraint with one job */
11139  SCIP_CALL( deleteTrivilCons(scip, cons, ndelconss, cutoff) );
11140 
11141  if( *cutoff || SCIPconsIsDeleted(cons) )
11142  return SCIP_OKAY;
11143 
11144  if( conshdlrdata->coeftightening )
11145  {
11146  /* try to tighten the capacity */
11147  SCIP_CALL( tightenCapacity(scip, cons, nchgcoefs, nchgsides) );
11148 
11149  /* try to tighten the coefficients */
11150  SCIP_CALL( tightenCoefs(scip, cons, nchgcoefs) );
11151  }
11152 
11153  assert(checkDemands(scip, cons) || *cutoff);
11154 
11155 #if 0
11156  SCIP_CALL( reformulateCons(scip, cons, naggrvars) );
11157 #endif
11158 
11159  return SCIP_OKAY;
11160 }
11161 
11162 /**@name TClique Graph callbacks
11163  *
11164  * @{
11165  */
11166 
11167 /** tclique graph data */
11168 struct TCLIQUE_Graph
11169 {
11170  SCIP_VAR** vars; /**< start time variables each of them is a node */
11171  SCIP_HASHMAP* varmap; /**< variable map, mapping variable to indux in vars array */
11172  SCIP_Bool** precedencematrix; /**< precedence adjacent matrix */
11173  SCIP_Bool** demandmatrix; /**< demand adjacent matrix */
11174  TCLIQUE_WEIGHT* weights; /**< weight of nodes */
11175  int* ninarcs; /**< number if in arcs for the precedence graph */
11176  int* noutarcs; /**< number if out arcs for the precedence graph */
11177  int* durations; /**< for each node the duration of the corresponding job */
11178  int nnodes; /**< number of nodes */
11179  int size; /**< size of the array */
11180 };
11181 
11182 /** gets number of nodes in the graph */
11183 static
11184 TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
11186  assert(tcliquegraph != NULL);
11187 
11188  return tcliquegraph->nnodes;
11189 }
11190 
11191 /** gets weight of nodes in the graph */
11192 static
11193 TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
11195  assert(tcliquegraph != NULL);
11196 
11197  return tcliquegraph->weights;
11198 }
11199 
11200 /** returns, whether the edge (node1, node2) is in the graph */
11201 static
11202 TCLIQUE_ISEDGE(tcliqueIsedgeClique)
11204  assert(tcliquegraph != NULL);
11205  assert(0 <= node1 && node1 < tcliquegraph->nnodes);
11206  assert(0 <= node2 && node2 < tcliquegraph->nnodes);
11207 
11208  /* check if an arc exits in the precedence graph */
11209  if( tcliquegraph->precedencematrix[node1][node2] || tcliquegraph->precedencematrix[node2][node1] )
11210  return TRUE;
11211 
11212  /* check if an edge exits in the non-overlapping graph */
11213  if( tcliquegraph->demandmatrix[node1][node2] )
11214  return TRUE;
11215 
11216  return FALSE;
11217 }
11218 
11219 /** selects all nodes from a given set of nodes which are adjacent to a given node
11220  * and returns the number of selected nodes
11221  */
11222 static
11223 TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
11225  int nadjnodes;
11226  int i;
11227 
11228  assert(tcliquegraph != NULL);
11229  assert(0 <= node && node < tcliquegraph->nnodes);
11230  assert(nnodes == 0 || nodes != NULL);
11231  assert(adjnodes != NULL);
11232 
11233  nadjnodes = 0;
11234 
11235  for( i = 0; i < nnodes; i++ )
11236  {
11237  /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
11238  assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
11239  assert(i == 0 || nodes[i-1] < nodes[i]);
11240 
11241  /* check if an edge exists */
11242  if( tcliqueIsedgeClique(tcliquegraph, node, nodes[i]) )
11243  {
11244  /* current node is adjacent to given node */
11245  adjnodes[nadjnodes] = nodes[i];
11246  nadjnodes++;
11247  }
11248  }
11249 
11250  return nadjnodes;
11251 }
11252 
11253 /** generates cuts using a clique found by algorithm for maximum weight clique
11254  * and decides whether to stop generating cliques with the algorithm for maximum weight clique
11255  */
11256 static
11257 TCLIQUE_NEWSOL(tcliqueNewsolClique)
11258 { /*lint --e{715}*/
11259  SCIPdebugMessage("####### max clique %d\n", cliqueweight);
11260 }
11261 
11262 /** print the tclique graph */
11263 #if 0
11264 static
11265 void tcliquePrint(
11266  SCIP* scip, /**< SCIP data structure */
11267  TCLIQUE_GRAPH* tcliquegraph /**< tclique graph */
11268  )
11269 {
11270  int nnodes;
11271  int i;
11272  int j;
11273 
11274  nnodes = tcliquegraph->nnodes;
11275 
11276  for( i = 0; i < nnodes; ++i )
11277  {
11278  for( j = 0; j < nnodes; ++j )
11279  {
11280  SCIPinfoMessage(scip, NULL, "(%d/%d) ", tcliquegraph->precedencematrix[i][j], tcliquegraph->demandmatrix[i][j]);
11281  }
11282  SCIPinfoMessage(scip, NULL, "\n");
11283  }
11284 }
11285 #endif
11286 
11287 /** @} */
11288 
11289 /** analyzes if the given variable lower bound condition implies a precedence condition w.r.t. given duration for the
11290  * job corresponding to variable bound variable (vlbvar)
11291  *
11292  * variable lower bound is given as: var >= vlbcoef * vlbvar + vlbconst
11293  */
11294 static
11296  SCIP* scip, /**< SCIP data structure */
11297  SCIP_VAR* vlbvar, /**< variable which bounds the variable from below */
11298  SCIP_Real vlbcoef, /**< variable bound coefficient */
11299  SCIP_Real vlbconst, /**< variable bound constant */
11300  int duration /**< duration of the variable bound variable */
11301  )
11302 {
11303  if( SCIPisEQ(scip, vlbcoef, 1.0) )
11304  {
11305  if( SCIPisGE(scip, vlbconst, (SCIP_Real) duration) )
11306  {
11307  /* if vlbcoef = 1 and vlbcoef >= duration -> precedence condition */
11308  return TRUE;
11309  }
11310  }
11311  else
11312  {
11313  SCIP_Real bound;
11314 
11315  bound = (duration - vlbcoef) / (vlbcoef - 1.0);
11316 
11317  if( SCIPisLT(scip, vlbcoef, 1.0) )
11318  {
11319  SCIP_Real ub;
11320 
11321  ub = SCIPvarGetUbLocal(vlbvar);
11322 
11323  /* if vlbcoef < 1 and ub(vlbvar) <= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11324  if( SCIPisLE(scip, ub, bound) )
11325  return TRUE;
11326  }
11327  else
11328  {
11329  SCIP_Real lb;
11330 
11331  assert(SCIPisGT(scip, vlbcoef, 1.0));
11332 
11333  lb = SCIPvarGetLbLocal(vlbvar);
11334 
11335  /* if vlbcoef > 1 and lb(vlbvar) >= (duration - vlbconst)/(vlbcoef - 1) -> precedence condition */
11336  if( SCIPisGE(scip, lb, bound) )
11337  return TRUE;
11338  }
11339  }
11340 
11341  return FALSE;
11342 }
11343 
11344 /** analyzes if the given variable upper bound condition implies a precedence condition w.r.t. given duration for the
11345  * job corresponding to variable which is bounded (var)
11346  *
11347  * variable upper bound is given as: var <= vubcoef * vubvar + vubconst
11348  */
11349 static
11351  SCIP* scip, /**< SCIP data structure */
11352  SCIP_VAR* var, /**< variable which is bound from above */
11353  SCIP_Real vubcoef, /**< variable bound coefficient */
11354  SCIP_Real vubconst, /**< variable bound constant */
11355  int duration /**< duration of the variable which is bounded from above */
11356  )
11357 {
11358  SCIP_Real vlbcoef;
11359  SCIP_Real vlbconst;
11360 
11361  /* convert the variable upper bound into an variable lower bound */
11362  vlbcoef = 1.0 / vubcoef;
11363  vlbconst = -vubconst / vubcoef;
11364 
11365  return impliesVlbPrecedenceCondition(scip, var, vlbcoef, vlbconst, duration);
11366 }
11367 
11368 /** get the corresponding index of the given variables; this in case of an active variable the problem index and for
11369  * others an index larger than the number if active variables
11370  */
11371 static
11373  SCIP* scip, /**< SCIP data structure */
11374  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11375  SCIP_VAR* var, /**< variable for which we want the index */
11376  int* idx /**< pointer to store the index */
11377  )
11378 {
11379  (*idx) = SCIPvarGetProbindex(var);
11380 
11381  if( (*idx) == -1 )
11382  {
11383  if( SCIPhashmapExists(tcliquegraph->varmap, (void*)var) )
11384  {
11385  (*idx) = SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var);
11386  }
11387  else
11388  {
11389  int pos;
11390  int v;
11391 
11392  /**@todo we might want to add the aggregation path to graph */
11393 
11394  /* check if we have to realloc memory */
11395  if( tcliquegraph->size == tcliquegraph->nnodes )
11396  {
11397  int size;
11398 
11399  size = SCIPcalcMemGrowSize(scip, tcliquegraph->nnodes+1);
11400  tcliquegraph->size = size;
11401 
11402  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->vars, size) );
11403  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix, size) );
11404  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix, size) );
11405  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->durations, size) );
11406  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->weights, size) );
11407 
11408  for( v = 0; v < tcliquegraph->nnodes; ++v )
11409  {
11410  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->precedencematrix[v], size) ); /*lint !e866*/
11411  SCIP_CALL( SCIPreallocBufferArray(scip, &tcliquegraph->demandmatrix[v], size) ); /*lint !e866*/
11412  }
11413  }
11414  assert(tcliquegraph->nnodes < tcliquegraph->size);
11415 
11416  pos = tcliquegraph->nnodes;
11417  assert(pos >= 0);
11418 
11419  tcliquegraph->durations[pos] = 0;
11420  tcliquegraph->weights[pos] = 0;
11421  tcliquegraph->vars[pos] = var;
11422 
11423  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->precedencematrix[pos], tcliquegraph->size) ); /*lint !e866*/
11424  BMSclearMemoryArray(tcliquegraph->precedencematrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11425 
11426  SCIP_CALL( SCIPallocBufferArray(scip, &tcliquegraph->demandmatrix[pos], tcliquegraph->size) ); /*lint !e866*/
11427  BMSclearMemoryArray(tcliquegraph->demandmatrix[pos], tcliquegraph->nnodes); /*lint !e866*/
11428 
11429  SCIP_CALL( SCIPhashmapInsertInt(tcliquegraph->varmap, (void*)var, pos) );
11430 
11431  tcliquegraph->nnodes++;
11432 
11433  for( v = 0; v < tcliquegraph->nnodes; ++v )
11434  {
11435  tcliquegraph->precedencematrix[v][pos] = 0;
11436  tcliquegraph->demandmatrix[v][pos] = 0;
11437  }
11438 
11439  (*idx) = tcliquegraph->nnodes;
11440  }
11441  }
11442  else
11443  {
11444  assert(*idx == SCIPhashmapGetImageInt(tcliquegraph->varmap, (void*)var));
11445  }
11446 
11447  assert(SCIPhashmapExists(tcliquegraph->varmap, (void*)var));
11448 
11449  return SCIP_OKAY;
11450 }
11451 
11452 /** use the variables bounds of SCIP to projected variables bound graph into a precedence garph
11453  *
11454  * Let d be the (assumed) duration of variable x and consider a variable bound of the form b * x + c <= y. This
11455  * variable bounds implies a precedence condition x -> y (meaning job y starts after job x is finished) if:
11456  *
11457  * (i) b = 1 and c >= d
11458  * (ii) b > 1 and lb(x) >= (d - c)/(b - 1)
11459  * (iii) b < 1 and ub(x) >= (d - c)/(b - 1)
11460  *
11461  */
11462 static
11464  SCIP* scip, /**< SCIP data structure */
11465  TCLIQUE_GRAPH* tcliquegraph /**< incompatibility graph */
11466  )
11467 {
11468  SCIP_VAR** vars;
11469  int nvars;
11470  int v;
11471 
11472  vars = SCIPgetVars(scip);
11473  nvars = SCIPgetNVars(scip);
11474 
11475  /* try to project each arc of the variable bound graph to precedence condition */
11476  for( v = 0; v < nvars; ++v )
11477  {
11478  SCIP_VAR** vbdvars;
11479  SCIP_VAR* var;
11480  SCIP_Real* vbdcoefs;
11481  SCIP_Real* vbdconsts;
11482  int nvbdvars;
11483  int idx1;
11484  int b;
11485 
11486  var = vars[v];
11487  assert(var != NULL);
11488 
11489  SCIP_CALL( getNodeIdx(scip, tcliquegraph, var, &idx1) );
11490  assert(idx1 >= 0);
11491 
11492  if( tcliquegraph->durations[idx1] == 0 )
11493  continue;
11494 
11495  vbdvars = SCIPvarGetVlbVars(var);
11496  vbdcoefs = SCIPvarGetVlbCoefs(var);
11497  vbdconsts = SCIPvarGetVlbConstants(var);
11498  nvbdvars = SCIPvarGetNVlbs(var);
11499 
11500  for( b = 0; b < nvbdvars; ++b )
11501  {
11502  int idx2;
11503 
11504  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11505  assert(idx2 >= 0);
11506 
11507  if( tcliquegraph->durations[idx2] == 0 )
11508  continue;
11509 
11510  if( impliesVlbPrecedenceCondition(scip, vbdvars[b], vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx2]) )
11511  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11512  }
11513 
11514  vbdvars = SCIPvarGetVubVars(var);
11515  vbdcoefs = SCIPvarGetVubCoefs(var);
11516  vbdconsts = SCIPvarGetVubConstants(var);
11517  nvbdvars = SCIPvarGetNVubs(var);
11518 
11519  for( b = 0; b < nvbdvars; ++b )
11520  {
11521  int idx2;
11522 
11523  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vbdvars[b], &idx2) );
11524  assert(idx2 >= 0);
11525 
11526  if( tcliquegraph->durations[idx2] == 0 )
11527  continue;
11528 
11529  if( impliesVubPrecedenceCondition(scip, var, vbdcoefs[b], vbdconsts[b], tcliquegraph->durations[idx1]) )
11530  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11531  }
11532 
11533  for( b = v+1; b < nvars; ++b )
11534  {
11535  int idx2;
11536 
11537  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[b], &idx2) );
11538  assert(idx2 >= 0);
11539 
11540  if( tcliquegraph->durations[idx2] == 0 )
11541  continue;
11542 
11543  /* check if the latest completion time of job1 is smaller than the earliest start time of job2 */
11544  if( SCIPisLE(scip, SCIPvarGetUbLocal(var) + tcliquegraph->durations[idx1], SCIPvarGetLbLocal(vars[b])) )
11545  tcliquegraph->precedencematrix[idx1][idx2] = TRUE;
11546 
11547  /* check if the latest completion time of job2 is smaller than the earliest start time of job1 */
11548  if( SCIPisLE(scip, SCIPvarGetUbLocal(vars[b]) + tcliquegraph->durations[idx2], SCIPvarGetLbLocal(var)) )
11549  tcliquegraph->precedencematrix[idx2][idx1] = TRUE;
11550  }
11551  }
11552 
11553  return SCIP_OKAY;
11554 }
11555 
11556 /** compute the transitive closer of the given graph and the number of in and out arcs */
11557 static
11558 void transitiveClosure(
11559  SCIP_Bool** adjmatrix, /**< adjacent matrix */
11560  int* ninarcs, /**< array to store the number of in arcs */
11561  int* noutarcs, /**< array to store the number of out arcs */
11562  int nnodes /**< number if nodes */
11563  )
11564 {
11565  int i;
11566  int j;
11567  int k;
11568 
11569  for( i = 0; i < nnodes; ++i )
11570  {
11571  for( j = 0; j < nnodes; ++j )
11572  {
11573  if( adjmatrix[i][j] )
11574  {
11575  ninarcs[j]++;
11576  noutarcs[i]++;
11577 
11578  for( k = 0; k < nnodes; ++k )
11579  {
11580  if( adjmatrix[j][k] )
11581  adjmatrix[i][k] = TRUE;
11582  }
11583  }
11584  }
11585  }
11586 }
11587 
11588 /** constructs a non-overlapping graph w.r.t. given durations and available cumulative constraints */
11589 static
11591  SCIP* scip, /**< SCIP data structure */
11592  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11593  SCIP_CONS** conss, /**< array of cumulative constraints */
11594  int nconss /**< number of cumulative constraints */
11595  )
11596 {
11597  int c;
11598 
11599  /* use the cumulative constraints to initialize the none overlapping graph */
11600  for( c = 0; c < nconss; ++c )
11601  {
11602  SCIP_CONSDATA* consdata;
11603  SCIP_VAR** vars;
11604  int* demands;
11605  int capacity;
11606  int nvars;
11607  int i;
11608 
11609  consdata = SCIPconsGetData(conss[c]);
11610  assert(consdata != NULL);
11611 
11612  vars = consdata->vars;
11613  demands = consdata->demands;
11614 
11615  nvars = consdata->nvars;
11616  capacity = consdata->capacity;
11617 
11618  SCIPdebugMsg(scip, "constraint <%s>\n", SCIPconsGetName(conss[c]));
11619 
11620  /* check pairwise if two jobs have a cumulative demand larger than the capacity */
11621  for( i = 0; i < nvars; ++i )
11622  {
11623  int idx1;
11624  int j;
11625 
11626  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[i], &idx1) );
11627  assert(idx1 >= 0);
11628 
11629  if( tcliquegraph->durations[idx1] == 0 || tcliquegraph->durations[idx1] > consdata->durations[i] )
11630  continue;
11631 
11632  for( j = i+1; j < nvars; ++j )
11633  {
11634  assert(consdata->durations[j] > 0);
11635 
11636  if( demands[i] + demands[j] > capacity )
11637  {
11638  int idx2;
11639  int est1;
11640  int est2;
11641  int lct1;
11642  int lct2;
11643 
11644  /* check if the effective horizon is large enough */
11645  est1 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[i]));
11646  est2 = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[j]));
11647 
11648  /* at least one of the jobs needs to start at hmin or later */
11649  if( est1 < consdata->hmin && est2 < consdata->hmin )
11650  continue;
11651 
11652  lct1 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[i])) + consdata->durations[i];
11653  lct2 = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[j])) + consdata->durations[j];
11654 
11655  /* at least one of the jobs needs to finish not later then hmin */
11656  if( lct1 > consdata->hmax && lct2 > consdata->hmax )
11657  continue;
11658 
11659  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[j], &idx2) );
11660  assert(idx2 >= 0);
11661  assert(idx1 != idx2);
11662 
11663  if( tcliquegraph->durations[idx2] == 0 || tcliquegraph->durations[idx2] > consdata->durations[j] )
11664  continue;
11665 
11666  SCIPdebugMsg(scip, " *** variable <%s> and variable <%s>\n", SCIPvarGetName(vars[i]), SCIPvarGetName(vars[j]));
11667 
11668  assert(tcliquegraph->durations[idx1] > 0);
11669  assert(tcliquegraph->durations[idx2] > 0);
11670 
11671  tcliquegraph->demandmatrix[idx1][idx2] = TRUE;
11672  tcliquegraph->demandmatrix[idx2][idx1] = TRUE;
11673  }
11674  }
11675  }
11676  }
11677 
11678  return SCIP_OKAY;
11679 }
11680 
11681 /** constructs a conflict set graph (undirected) which contains for each job a node and edge if the corresponding pair
11682  * of jobs cannot run in parallel
11683  */
11684 static
11686  SCIP* scip, /**< SCIP data structure */
11687  TCLIQUE_GRAPH* tcliquegraph, /**< incompatibility graph */
11688  SCIP_CONS** conss, /**< array of cumulative constraints */
11689  int nconss /**< number of cumulative constraints */
11690  )
11691 {
11692  assert(scip != NULL);
11693  assert(tcliquegraph != NULL);
11694 
11695  /* use the variables bounds of SCIP to project the variables bound graph inot a precedence graph */
11696  SCIP_CALL( projectVbd(scip, tcliquegraph) );
11697 
11698  /* compute the transitive closure of the precedence graph and the number of in and out arcs */
11699  transitiveClosure(tcliquegraph->precedencematrix, tcliquegraph->ninarcs, tcliquegraph->noutarcs, tcliquegraph->nnodes);
11700 
11701  /* constraints non-overlapping graph */
11702  SCIP_CALL( constraintNonOverlappingGraph(scip, tcliquegraph, conss, nconss) );
11703 
11704  return SCIP_OKAY;
11705 }
11706 
11707 /** create cumulative constraint from conflict set */
11708 static
11710  SCIP* scip, /**< SCIP data structure */
11711  const char* name, /**< constraint name */
11712  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11713  int* cliquenodes, /**< array storing the indecies of the nodes belonging to the clique */
11714  int ncliquenodes /**< number of nodes in the clique */
11715  )
11716 {
11717  SCIP_CONS* cons;
11718  SCIP_VAR** vars;
11719  int* durations;
11720  int* demands;
11721  int v;
11722 
11723  SCIP_CALL( SCIPallocBufferArray(scip, &vars, ncliquenodes) );
11724  SCIP_CALL( SCIPallocBufferArray(scip, &durations, ncliquenodes) );
11725  SCIP_CALL( SCIPallocBufferArray(scip, &demands, ncliquenodes) );
11726 
11727  SCIPsortInt(cliquenodes, ncliquenodes);
11728 
11729  /* collect variables, durations, and demands */
11730  for( v = 0; v < ncliquenodes; ++v )
11731  {
11732  durations[v] = tcliquegraph->durations[cliquenodes[v]];
11733  assert(durations[v] > 0);
11734  demands[v] = 1;
11735  vars[v] = tcliquegraph->vars[cliquenodes[v]];
11736  }
11737 
11738  /* create (unary) cumulative constraint */
11739  SCIP_CALL( SCIPcreateConsCumulative(scip, &cons, name, ncliquenodes, vars, durations, demands, 1,
11741 
11742  SCIP_CALL( SCIPaddCons(scip, cons) );
11743  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11744 
11745  /* free buffers */
11746  SCIPfreeBufferArray(scip, &demands);
11747  SCIPfreeBufferArray(scip, &durations);
11748  SCIPfreeBufferArray(scip, &vars);
11749 
11750  return SCIP_OKAY;
11751 }
11752 
11753 /** search for cumulative constrainst */
11754 static
11756  SCIP* scip, /**< SCIP data structure */
11757  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11758  int* naddconss /**< pointer to store the number of added constraints */
11759  )
11760 {
11761  TCLIQUE_STATUS tcliquestatus;
11762  SCIP_Bool* precedencerow;
11763  SCIP_Bool* precedencecol;
11764  SCIP_Bool* demandrow;
11765  SCIP_Bool* demandcol;
11766  SCIP_HASHTABLE* covered;
11767  int* cliquenodes;
11768  int ncliquenodes;
11769  int cliqueweight;
11770  int ntreenodes;
11771  int nnodes;
11772  int nconss;
11773  int v;
11774 
11775  nnodes = tcliquegraph->nnodes;
11776  nconss = 0;
11777 
11778  /* initialize the weight of each job with its duration */
11779  for( v = 0; v < nnodes; ++v )
11780  {
11781  tcliquegraph->weights[v] = tcliquegraph->durations[v];
11782  }
11783 
11784  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11785  SCIP_CALL( SCIPallocBufferArray(scip, &precedencerow, nnodes) );
11786  SCIP_CALL( SCIPallocBufferArray(scip, &precedencecol, nnodes) );
11787  SCIP_CALL( SCIPallocBufferArray(scip, &demandrow, nnodes) );
11788  SCIP_CALL( SCIPallocBufferArray(scip, &demandcol, nnodes) );
11789 
11790  /* create a hash table to store all start time variables which are already covered by at least one clique */
11791  SCIP_CALL( SCIPhashtableCreate(&covered, SCIPblkmem(scip), nnodes,
11792  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
11793 
11794  /* for each variables/job we are ... */
11795  for( v = 0; v < nnodes && !SCIPisStopped(scip); ++v )
11796  {
11797  char name[SCIP_MAXSTRLEN];
11798  int c;
11799 
11800  /* jobs with zero durations are skipped */
11801  if( tcliquegraph->durations[v] == 0 )
11802  continue;
11803 
11804  /* check if the start time variable is already covered by at least one clique */
11805  if( SCIPhashtableExists(covered, tcliquegraph->vars[v]) )
11806  continue;
11807 
11808  SCIPdebugMsg(scip, "********** variable <%s>\n", SCIPvarGetName(tcliquegraph->vars[v]));
11809 
11810  /* temporarily remove the connection via the precedence graph */
11811  for( c = 0; c < nnodes; ++c )
11812  {
11813  precedencerow[c] = tcliquegraph->precedencematrix[v][c];
11814  precedencecol[c] = tcliquegraph->precedencematrix[c][v];
11815 
11816  demandrow[c] = tcliquegraph->demandmatrix[v][c];
11817  demandcol[c] = tcliquegraph->demandmatrix[c][v];
11818 
11819 #if 0
11820  if( precedencerow[c] || precedencecol[c] )
11821  {
11822  tcliquegraph->demandmatrix[v][c] = FALSE;
11823  tcliquegraph->demandmatrix[c][v] = FALSE;
11824  }
11825 #endif
11826 
11827  tcliquegraph->precedencematrix[c][v] = FALSE;
11828  tcliquegraph->precedencematrix[v][c] = FALSE;
11829  }
11830 
11831  /* find (heuristically) maximum cliques which includes node v */
11832  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11833  tcliquegraph, tcliqueNewsolClique, NULL,
11834  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11835  10000, 1000, 1000, v, &ntreenodes, &tcliquestatus);
11836 
11837  SCIPdebugMsg(scip, "tree nodes %d clique size %d (weight %d, status %d)\n", ntreenodes, ncliquenodes, cliqueweight, tcliquestatus);
11838 
11839  if( ncliquenodes == 1 )
11840  continue;
11841 
11842  /* construct constraint name */
11843  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "nooverlap_%d_%d", SCIPgetNRuns(scip), nconss);
11844 
11845  SCIP_CALL( createCumulativeCons(scip, name, tcliquegraph, cliquenodes, ncliquenodes) );
11846  nconss++;
11847 
11848  /* all start time variable to covered hash table */
11849  for( c = 0; c < ncliquenodes; ++c )
11850  {
11851  SCIP_CALL( SCIPhashtableInsert(covered, tcliquegraph->vars[cliquenodes[c]]) );
11852  }
11853 
11854  /* copy the precedence relations back */
11855  for( c = 0; c < nnodes; ++c )
11856  {
11857  tcliquegraph->precedencematrix[v][c] = precedencerow[c];
11858  tcliquegraph->precedencematrix[c][v] = precedencecol[c];
11859 
11860  tcliquegraph->demandmatrix[v][c] = demandrow[c];
11861  tcliquegraph->demandmatrix[c][v] = demandcol[c];
11862  }
11863  }
11864 
11865  SCIPhashtableFree(&covered);
11866 
11867  SCIPfreeBufferArray(scip, &demandcol);
11868  SCIPfreeBufferArray(scip, &demandrow);
11869  SCIPfreeBufferArray(scip, &precedencecol);
11870  SCIPfreeBufferArray(scip, &precedencerow);
11871  SCIPfreeBufferArray(scip, &cliquenodes);
11872 
11873  (*naddconss) += nconss;
11874 
11875  /* for the statistic we count the number added disjunctive constraints */
11876  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddeddisjunctives += nconss );
11877 
11878  return SCIP_OKAY;
11879 }
11880 
11881 /** create precedence constraint (as variable bound constraint */
11882 static
11884  SCIP* scip, /**< SCIP data structure */
11885  const char* name, /**< constraint name */
11886  SCIP_VAR* var, /**< variable x that has variable bound */
11887  SCIP_VAR* vbdvar, /**< binary, integer or implicit integer bounding variable y */
11888  int distance /**< minimum distance between the start time of the job corresponding to var and the job corresponding to vbdvar */
11889  )
11890 {
11891  SCIP_CONS* cons;
11892 
11893  /* create variable bound constraint */
11894  SCIP_CALL( SCIPcreateConsVarbound(scip, &cons, name, var, vbdvar, -1.0, -SCIPinfinity(scip), -(SCIP_Real)distance,
11896 
11897  SCIPdebugPrintCons(scip, cons, NULL);
11898 
11899  /* add constraint to problem and release it */
11900  SCIP_CALL( SCIPaddCons(scip, cons) );
11901  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
11902 
11903  return SCIP_OKAY;
11904 }
11905 
11906 /** compute a minimum distance between the start times of the two given jobs and post it as variable bound constraint */
11907 static
11909  SCIP* scip, /**< SCIP data structure */
11910  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
11911  int source, /**< index of the source node */
11912  int sink, /**< index of the sink node */
11913  int* naddconss /**< pointer to store the number of added constraints */
11914  )
11915 {
11916  TCLIQUE_WEIGHT cliqueweight;
11917  TCLIQUE_STATUS tcliquestatus;
11918  SCIP_VAR** vars;
11919  int* cliquenodes;
11920  int nnodes;
11921  int lct;
11922  int est;
11923  int i;
11924 
11925  int ntreenodes;
11926  int ncliquenodes;
11927 
11928  /* check if source and sink are connencted */
11929  if( !tcliquegraph->precedencematrix[source][sink] )
11930  return SCIP_OKAY;
11931 
11932  nnodes = tcliquegraph->nnodes;
11933  vars = tcliquegraph->vars;
11934 
11935  /* reset the weights to zero */
11936  BMSclearMemoryArray(tcliquegraph->weights, nnodes);
11937 
11938  /* get latest completion time (lct) of the source and the earliest start time (est) of sink */
11939  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(vars[source])) + tcliquegraph->durations[source];
11940  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(vars[sink]));
11941 
11942  /* weight all jobs which run for sure between source and sink with their duration */
11943  for( i = 0; i < nnodes; ++i )
11944  {
11945  SCIP_VAR* var;
11946  int duration;
11947 
11948  var = vars[i];
11949  assert(var != NULL);
11950 
11951  duration = tcliquegraph->durations[i];
11952 
11953  if( i == source || i == sink )
11954  {
11955  /* source and sink are not weighted */
11956  tcliquegraph->weights[i] = 0;
11957  }
11958  else if( tcliquegraph->precedencematrix[source][i] && tcliquegraph->precedencematrix[i][sink] )
11959  {
11960  /* job i runs after source and before sink */
11961  tcliquegraph->weights[i] = duration;
11962  }
11963  else if( lct <= SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var))
11964  && est >= SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration )
11965  {
11966  /* job i run in between due the bounds of the start time variables */
11967  tcliquegraph->weights[i] = duration;
11968  }
11969  else
11970  tcliquegraph->weights[i] = 0;
11971  }
11972 
11973  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nnodes) );
11974 
11975  /* find (heuristically) maximum cliques */
11976  tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
11977  tcliquegraph, tcliqueNewsolClique, NULL,
11978  cliquenodes, &ncliquenodes, &cliqueweight, 1, 1,
11979  10000, 1000, 1000, -1, &ntreenodes, &tcliquestatus);
11980 
11981  if( ncliquenodes > 1 )
11982  {
11983  char name[SCIP_MAXSTRLEN];
11984  int distance;
11985 
11986  /* construct constraint name */
11987  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), *naddconss);
11988 
11989  /* the minimum distance between the start times of source job and the sink job is the clique weight plus the
11990  * duration of the source job
11991  */
11992  distance = cliqueweight + tcliquegraph->durations[source];
11993 
11994  SCIP_CALL( createPrecedenceCons(scip, name, vars[source], vars[sink], distance) );
11995  (*naddconss)++;
11996  }
11997 
11998  SCIPfreeBufferArray(scip, &cliquenodes);
11999 
12000  return SCIP_OKAY;
12001 }
12002 
12003 /** search for precedence constraints
12004  *
12005  * for each arc of the transitive closure of the precedence graph, we are computing a minimum distance between the
12006  * corresponding two jobs
12007  */
12008 static
12010  SCIP* scip, /**< SCIP data structure */
12011  TCLIQUE_GRAPH* tcliquegraph, /**< conflict set graph */
12012  int* naddconss /**< pointer to store the number of added constraints */
12013  )
12014 {
12015  int* sources;
12016  int* sinks;
12017  int nconss;
12018  int nnodes;
12019  int nsources;
12020  int nsinks;
12021  int i;
12022 
12023  nnodes = tcliquegraph->nnodes;
12024  nconss = 0;
12025 
12026  nsources = 0;
12027  nsinks = 0;
12028 
12029  SCIP_CALL( SCIPallocBufferArray(scip, &sources, nnodes) );
12030  SCIP_CALL( SCIPallocBufferArray(scip, &sinks, nnodes) );
12031 
12032  /* first collect all sources and sinks */
12033  for( i = 0; i < nnodes; ++i )
12034  {
12035  if( tcliquegraph->ninarcs[i] == 0 )
12036  {
12037  sources[nsources] = i;
12038  nsources++;
12039  }
12040 
12041  if( tcliquegraph->ninarcs[i] == 0 )
12042  {
12043  sinks[nsinks] = i;
12044  nsinks++;
12045  }
12046  }
12047 
12048  /* compute for each node a minimum distance to each sources and each sink */
12049  for( i = 0; i < nnodes && !SCIPisStopped(scip); ++i )
12050  {
12051  int j;
12052 
12053  for( j = 0; j < nsources && !SCIPisStopped(scip); ++j )
12054  {
12055  SCIP_CALL( computeMinDistance(scip, tcliquegraph, sources[j], i, &nconss) );
12056  }
12057 
12058  for( j = 0; j < nsinks && !SCIPisStopped(scip); ++j )
12059  {
12060  SCIP_CALL( computeMinDistance(scip, tcliquegraph, i, sinks[j], &nconss) );
12061  }
12062  }
12063 
12064  (*naddconss) += nconss;
12065 
12066  /* for the statistic we count the number added variable constraints */
12067  SCIPstatistic( SCIPconshdlrGetData(SCIPfindConshdlr(scip, CONSHDLR_NAME))->naddedvarbounds += nconss );
12068 
12069  SCIPfreeBufferArray(scip, &sinks);
12070  SCIPfreeBufferArray(scip, &sources);
12071 
12072  return SCIP_OKAY;
12073 }
12074 
12075 /** initialize the assumed durations for each variable */
12076 static
12078  SCIP* scip, /**< SCIP data structure */
12079  TCLIQUE_GRAPH* tcliquegraph, /**< the incompatibility graph */
12080  SCIP_CONS** conss, /**< cumulative constraints */
12081  int nconss /**< number of cumulative constraints */
12082  )
12083 {
12084  int c;
12085 
12086  /* use the cumulative structure to define the duration we are using for each job */
12087  for( c = 0; c < nconss; ++c )
12088  {
12089  SCIP_CONSDATA* consdata;
12090  SCIP_VAR** vars;
12091  int nvars;
12092  int v;
12093 
12094  consdata = SCIPconsGetData(conss[c]);
12095  assert(consdata != NULL);
12096 
12097  vars = consdata->vars;
12098  nvars = consdata->nvars;
12099 
12100  for( v = 0; v < nvars; ++v )
12101  {
12102  int idx;
12103 
12104  SCIP_CALL( getNodeIdx(scip, tcliquegraph, vars[v], &idx) );
12105  assert(idx >= 0);
12106 
12107  /**@todo For the test sets, which we are considere, the durations are independent of the cumulative
12108  * constaints. Meaning each job has a fixed duration which is the same for all cumulative constraints. In
12109  * general this is not the case. Therefore, the question would be which duration should be used?
12110  */
12111  tcliquegraph->durations[idx] = MAX(tcliquegraph->durations[idx], consdata->durations[v]);
12112  assert(tcliquegraph->durations[idx] > 0);
12113  }
12114  }
12115 
12116  return SCIP_OKAY;
12117 }
12118 
12119 /** create tclique graph */
12120 static
12122  SCIP* scip, /**< SCIP data structure */
12123  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12124  )
12125 {
12126  SCIP_VAR** vars;
12127  SCIP_HASHMAP* varmap;
12128  SCIP_Bool** precedencematrix;
12129  SCIP_Bool** demandmatrix;
12130  int* ninarcs;
12131  int* noutarcs;
12132  int* durations;
12133  int* weights;
12134  int nvars;
12135  int v;
12136 
12137  vars = SCIPgetVars(scip);
12138  nvars = SCIPgetNVars(scip);
12139 
12140  /* allocate memory for the tclique graph data structure */
12141  SCIP_CALL( SCIPallocBuffer(scip, tcliquegraph) );
12142 
12143  /* create the variable mapping hash map */
12144  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
12145 
12146  /* each active variables get a node in the graph */
12147  SCIP_CALL( SCIPduplicateBufferArray(scip, &(*tcliquegraph)->vars, vars, nvars) );
12148 
12149  /* allocate memory for the projected variables bound graph and the none overlapping graph */
12150  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix, nvars) );
12151  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix, nvars) );
12152 
12153  /* array to buffer the weights of the nodes for the maximum weighted clique computation */
12154  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
12155  BMSclearMemoryArray(weights, nvars);
12156 
12157  /* array to store the number of in arc of the precedence graph */
12158  SCIP_CALL( SCIPallocBufferArray(scip, &ninarcs, nvars) );
12159  BMSclearMemoryArray(ninarcs, nvars);
12160 
12161  /* array to store the number of out arc of the precedence graph */
12162  SCIP_CALL( SCIPallocBufferArray(scip, &noutarcs, nvars) );
12163  BMSclearMemoryArray(noutarcs, nvars);
12164 
12165  /* array to store the used duration for each node */
12166  SCIP_CALL( SCIPallocBufferArray(scip, &durations, nvars) );
12167  BMSclearMemoryArray(durations, nvars);
12168 
12169  for( v = 0; v < nvars; ++v )
12170  {
12171  SCIP_VAR* var;
12172 
12173  var = vars[v];
12174  assert(var != NULL);
12175 
12176  SCIP_CALL( SCIPallocBufferArray(scip, &precedencematrix[v], nvars) ); /*lint !e866*/
12177  BMSclearMemoryArray(precedencematrix[v], nvars); /*lint !e866*/
12178 
12179  SCIP_CALL( SCIPallocBufferArray(scip, &demandmatrix[v], nvars) ); /*lint !e866*/
12180  BMSclearMemoryArray(demandmatrix[v], nvars); /*lint !e866*/
12181 
12182  /* insert all active variables into the garph */
12183  assert(SCIPvarGetProbindex(var) == v);
12184  SCIP_CALL( SCIPhashmapInsertInt(varmap, (void*)var, v) );
12185  }
12186 
12187  (*tcliquegraph)->nnodes = nvars;
12188  (*tcliquegraph)->varmap = varmap;
12189  (*tcliquegraph)->precedencematrix = precedencematrix;
12190  (*tcliquegraph)->demandmatrix = demandmatrix;
12191  (*tcliquegraph)->weights = weights;
12192  (*tcliquegraph)->ninarcs = ninarcs;
12193  (*tcliquegraph)->noutarcs = noutarcs;
12194  (*tcliquegraph)->durations = durations;
12195  (*tcliquegraph)->size = nvars;
12196 
12197  return SCIP_OKAY;
12198 }
12199 
12200 /** frees the tclique graph */
12201 static
12202 void freeTcliqueGraph(
12203  SCIP* scip, /**< SCIP data structure */
12204  TCLIQUE_GRAPH** tcliquegraph /**< reference to the incompatibility graph */
12205  )
12206 {
12207  int v;
12208 
12209  for( v = (*tcliquegraph)->nnodes-1; v >= 0; --v )
12210  {
12211  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix[v]);
12212  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix[v]);
12213  }
12214 
12215  SCIPfreeBufferArray(scip, &(*tcliquegraph)->durations);
12216  SCIPfreeBufferArray(scip, &(*tcliquegraph)->noutarcs);
12217  SCIPfreeBufferArray(scip, &(*tcliquegraph)->ninarcs);
12218  SCIPfreeBufferArray(scip, &(*tcliquegraph)->weights);
12219  SCIPfreeBufferArray(scip, &(*tcliquegraph)->demandmatrix);
12220  SCIPfreeBufferArray(scip, &(*tcliquegraph)->precedencematrix);
12221  SCIPfreeBufferArray(scip, &(*tcliquegraph)->vars);
12222  SCIPhashmapFree(&(*tcliquegraph)->varmap);
12223 
12224  SCIPfreeBuffer(scip, tcliquegraph);
12225 }
12226 
12227 /** construct an incompatibility graph and search for precedence constraints (variables bounds) and unary cumulative
12228  * constrains (disjunctive constraint)
12229  */
12230 static
12232  SCIP* scip, /**< SCIP data structure */
12233  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
12234  SCIP_CONS** conss, /**< array of cumulative constraints */
12235  int nconss, /**< number of cumulative constraints */
12236  int* naddconss /**< pointer to store the number of added constraints */
12237  )
12238 {
12239  TCLIQUE_GRAPH* tcliquegraph;
12240 
12241  /* create tclique graph */
12242  SCIP_CALL( createTcliqueGraph(scip, &tcliquegraph) );
12243 
12244  /* define for each job a duration */
12245  SCIP_CALL( initializeDurations(scip, tcliquegraph, conss, nconss) );
12246 
12247  /* constuct incompatibility graph */
12248  SCIP_CALL( constructIncompatibilityGraph(scip, tcliquegraph, conss, nconss) );
12249 
12250  /* search for new precedence constraints */
12251  if( conshdlrdata->detectvarbounds )
12252  {
12253  SCIP_CALL( findPrecedenceConss(scip, tcliquegraph, naddconss) );
12254  }
12255 
12256  /* search for new cumulative constraints */
12257  if( conshdlrdata->detectdisjunctive )
12258  {
12259  SCIP_CALL( findCumulativeConss(scip, tcliquegraph, naddconss) );
12260  }
12261 
12262  /* free tclique graph data structure */
12263  freeTcliqueGraph(scip, &tcliquegraph);
12264 
12265  return SCIP_OKAY;
12266 }
12267 
12268 /** compute the constraint signature which is used to detect constraints which contain potentially the same set of variables */
12269 static
12271  SCIP_CONSDATA* consdata /**< cumulative constraint data */
12272  )
12273 {
12274  SCIP_VAR** vars;
12275  int nvars;
12276  int v;
12277 
12278  if( consdata->validsignature )
12279  return;
12280 
12281  vars = consdata->vars;
12282  nvars = consdata->nvars;
12283 
12284  for( v = 0; v < nvars; ++v )
12285  {
12286  consdata->signature |= ((unsigned int)1 << ((unsigned int)SCIPvarGetIndex(vars[v]) % (sizeof(unsigned int) * 8)));
12287  }
12288 
12289  consdata->validsignature = TRUE;
12290 }
12291 
12292 /** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
12293 static
12294 SCIP_DECL_SORTINDCOMP(consdataCompVar)
12295 { /*lint --e{715}*/
12296  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
12297 
12298  assert(consdata != NULL);
12299  assert(0 <= ind1 && ind1 < consdata->nvars);
12300  assert(0 <= ind2 && ind2 < consdata->nvars);
12301 
12302  return SCIPvarCompare(consdata->vars[ind1], consdata->vars[ind2]);
12303 }
12304 
12305 /** run a pairwise comparison */
12306 static
12308  SCIP* scip, /**< SCIP data structure */
12309  SCIP_CONS** conss, /**< array of cumulative constraints */
12310  int nconss, /**< number of cumulative constraints */
12311  int* ndelconss /**< pointer to store the number of deletedconstraints */
12312  )
12313 {
12314  int i;
12315  int j;
12316 
12317  for( i = 0; i < nconss; ++i )
12318  {
12319  SCIP_CONSDATA* consdata0;
12320  SCIP_CONS* cons0;
12321 
12322  cons0 = conss[i];
12323  assert(cons0 != NULL);
12324 
12325  consdata0 = SCIPconsGetData(cons0);
12326  assert(consdata0 != NULL);
12327 
12328  consdataCalcSignature(consdata0);
12329  assert(consdata0->validsignature);
12330 
12331  for( j = i+1; j < nconss; ++j )
12332  {
12333  SCIP_CONSDATA* consdata1;
12334  SCIP_CONS* cons1;
12335 
12336  cons1 = conss[j];
12337  assert(cons1 != NULL);
12338 
12339  consdata1 = SCIPconsGetData(cons1);
12340  assert(consdata1 != NULL);
12341 
12342  if( consdata0->capacity != consdata1->capacity )
12343  continue;
12344 
12345  consdataCalcSignature(consdata1);
12346  assert(consdata1->validsignature);
12347 
12348  if( (consdata1->signature & (~consdata0->signature)) == 0 )
12349  {
12350  SCIPswapPointers((void**)&consdata0, (void**)&consdata1);
12351  SCIPswapPointers((void**)&cons0, (void**)&cons1);
12352  assert((consdata0->signature & (~consdata1->signature)) == 0);
12353  }
12354 
12355  if( (consdata0->signature & (~consdata1->signature)) == 0 )
12356  {
12357  int* perm0;
12358  int* perm1;
12359  int v0;
12360  int v1;
12361 
12362  if( consdata0->nvars > consdata1->nvars )
12363  continue;
12364 
12365  if( consdata0->hmin < consdata1->hmin )
12366  continue;
12367 
12368  if( consdata0->hmax > consdata1->hmax )
12369  continue;
12370 
12371  SCIP_CALL( SCIPallocBufferArray(scip, &perm0, consdata0->nvars) );
12372  SCIP_CALL( SCIPallocBufferArray(scip, &perm1, consdata1->nvars) );
12373 
12374  /* call sorting method */
12375  SCIPsort(perm0, consdataCompVar, (void*)consdata0, consdata0->nvars);
12376  SCIPsort(perm1, consdataCompVar, (void*)consdata1, consdata1->nvars);
12377 
12378  for( v0 = 0, v1 = 0; v0 < consdata0->nvars && v1 < consdata1->nvars; )
12379  {
12380  SCIP_VAR* var0;
12381  SCIP_VAR* var1;
12382  int idx0;
12383  int idx1;
12384  int comp;
12385 
12386  idx0 = perm0[v0];
12387  idx1 = perm1[v1];
12388 
12389  var0 = consdata0->vars[idx0];
12390 
12391  var1 = consdata1->vars[idx1];
12392 
12393  comp = SCIPvarCompare(var0, var1);
12394 
12395  if( comp == 0 )
12396  {
12397  int duration0;
12398  int duration1;
12399  int demand0;
12400  int demand1;
12401 
12402  demand0 = consdata0->demands[idx0];
12403  duration0 = consdata0->durations[idx0];
12404 
12405  demand1 = consdata1->demands[idx1];
12406  duration1 = consdata1->durations[idx1];
12407 
12408  if( demand0 != demand1 )
12409  break;
12410 
12411  if( duration0 != duration1 )
12412  break;
12413 
12414  v0++;
12415  v1++;
12416  }
12417  else if( comp > 0 )
12418  v1++;
12419  else
12420  break;
12421  }
12422 
12423  if( v0 == consdata0->nvars )
12424  {
12425  if( SCIPconsIsChecked(cons0) && !SCIPconsIsChecked(cons1) )
12426  {
12427  initializeLocks(consdata1, TRUE);
12428  }
12429 
12430  /* coverity[swapped_arguments] */
12431  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
12432 
12433  SCIP_CALL( SCIPdelCons(scip, cons0) );
12434  (*ndelconss)++;
12435  }
12436 
12437  SCIPfreeBufferArray(scip, &perm1);
12438  SCIPfreeBufferArray(scip, &perm0);
12439  }
12440  }
12441  }
12442 
12443  return SCIP_OKAY;
12444 }
12445 
12446 /** strengthen the variable bounds using the cumulative condition */
12447 static
12449  SCIP* scip, /**< SCIP data structure */
12450  SCIP_CONS* cons, /**< constraint to propagate */
12451  int* nchgbds, /**< pointer to store the number of changed bounds */
12452  int* naddconss /**< pointer to store the number of added constraints */
12453  )
12454 {
12455  SCIP_CONSDATA* consdata;
12456  SCIP_VAR** vars;
12457  int* durations;
12458  int* demands;
12459  int capacity;
12460  int nvars;
12461  int nconss;
12462  int i;
12463 
12464  consdata = SCIPconsGetData(cons);
12465  assert(consdata != NULL);
12466 
12467  /* check if the variable bounds got already strengthen by the cumulative constraint */
12468  if( consdata->varbounds )
12469  return SCIP_OKAY;
12470 
12471  vars = consdata->vars;
12472  durations = consdata->durations;
12473  demands = consdata->demands;
12474  capacity = consdata->capacity;
12475  nvars = consdata->nvars;
12476 
12477  nconss = 0;
12478 
12479  for( i = 0; i < nvars && !SCIPisStopped(scip); ++i )
12480  {
12481  SCIP_VAR** vbdvars;
12482  SCIP_VAR* var;
12483  SCIP_Real* vbdcoefs;
12484  SCIP_Real* vbdconsts;
12485  int nvbdvars;
12486  int b;
12487  int j;
12488 
12489  var = consdata->vars[i];
12490  assert(var != NULL);
12491 
12492  vbdvars = SCIPvarGetVlbVars(var);
12493  vbdcoefs = SCIPvarGetVlbCoefs(var);
12494  vbdconsts = SCIPvarGetVlbConstants(var);
12495  nvbdvars = SCIPvarGetNVlbs(var);
12496 
12497  for( b = 0; b < nvbdvars; ++b )
12498  {
12499  if( SCIPisEQ(scip, vbdcoefs[b], 1.0) )
12500  {
12501  if( SCIPconvertRealToInt(scip, vbdconsts[b]) > -durations[i] )
12502  {
12503  for( j = 0; j < nvars; ++j )
12504  {
12505  if( vars[j] == vbdvars[b] )
12506  break;
12507  }
12508  if( j == nvars )
12509  continue;
12510 
12511  if( demands[i] + demands[j] > capacity && SCIPconvertRealToInt(scip, vbdconsts[b]) < durations[j] )
12512  {
12513  SCIP_Bool infeasible;
12514  char name[SCIP_MAXSTRLEN];
12515  int nlocalbdchgs;
12516 
12517  SCIPdebugMsg(scip, "<%s>[%d] + %g <= <%s>[%d]\n", SCIPvarGetName(vbdvars[b]), durations[j], vbdconsts[b], SCIPvarGetName(var), durations[i]);
12518 
12519  /* construct constraint name */
12520  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "varbound_%d_%d", SCIPgetNRuns(scip), nconss);
12521 
12522  SCIP_CALL( createPrecedenceCons(scip, name, vars[j], vars[i], durations[j]) );
12523  nconss++;
12524 
12525  SCIP_CALL( SCIPaddVarVlb(scip, var, vbdvars[b], 1.0, (SCIP_Real) durations[j], &infeasible, &nlocalbdchgs) );
12526  assert(!infeasible);
12527 
12528  (*nchgbds) += nlocalbdchgs;
12529  }
12530  }
12531  }
12532  }
12533  }
12534 
12535  (*naddconss) += nconss;
12536 
12537  consdata->varbounds = TRUE;
12538 
12539  return SCIP_OKAY;
12540 }
12541 
12542 /** helper function to enforce constraints */
12543 static
12545  SCIP* scip, /**< SCIP data structure */
12546  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
12547  SCIP_CONS** conss, /**< constraints to process */
12548  int nconss, /**< number of constraints */
12549  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
12550  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
12551  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
12552  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
12553  )
12554 {
12555  SCIP_CONSHDLRDATA* conshdlrdata;
12556 
12557  assert(conshdlr != NULL);
12558  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12559  assert(nconss == 0 || conss != NULL);
12560  assert(result != NULL);
12561 
12562  if( solinfeasible )
12563  {
12564  *result = SCIP_INFEASIBLE;
12565  return SCIP_OKAY;
12566  }
12567 
12568  SCIPdebugMsg(scip, "constraint enforcing %d useful cumulative constraints of %d constraints for %s solution\n", nusefulconss, nconss,
12569  sol == NULL ? "LP" : "relaxation");
12570 
12571  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12572  assert(conshdlrdata != NULL);
12573 
12574  (*result) = SCIP_FEASIBLE;
12575 
12576  if( conshdlrdata->usebinvars )
12577  {
12578  SCIP_Bool separated;
12579  SCIP_Bool cutoff;
12580  int c;
12581 
12582  separated = FALSE;
12583 
12584  /* first check if a constraints is violated */
12585  for( c = 0; c < nusefulconss; ++c )
12586  {
12587  SCIP_CONS* cons;
12588  SCIP_Bool violated;
12589 
12590  cons = conss[c];
12591  assert(cons != NULL);
12592 
12593  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12594 
12595  if( !violated )
12596  continue;
12597 
12598  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12599  if ( cutoff )
12600  {
12601  *result = SCIP_CUTOFF;
12602  return SCIP_OKAY;
12603  }
12604  }
12605 
12606  for( ; c < nconss && !separated; ++c )
12607  {
12608  SCIP_CONS* cons;
12609  SCIP_Bool violated;
12610 
12611  cons = conss[c];
12612  assert(cons != NULL);
12613 
12614  SCIP_CALL( checkCons(scip, cons, sol, &violated, FALSE) );
12615 
12616  if( !violated )
12617  continue;
12618 
12619  SCIP_CALL( separateConsBinaryRepresentation(scip, cons, sol, &separated, &cutoff) );
12620  if ( cutoff )
12621  {
12622  *result = SCIP_CUTOFF;
12623  return SCIP_OKAY;
12624  }
12625  }
12626 
12627  if( separated )
12628  (*result) = SCIP_SEPARATED;
12629  }
12630  else
12631  {
12632  SCIP_CALL( enforceSolution(scip, conss, nconss, sol, conshdlrdata->fillbranchcands, result) );
12633  }
12634 
12635  return SCIP_OKAY;
12636 }
12637 
12638 /**@} */
12639 
12640 
12641 /**@name Callback methods of constraint handler
12642  *
12643  * @{
12644  */
12645 
12646 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12647 static
12648 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCumulative)
12649 { /*lint --e{715}*/
12650  assert(scip != NULL);
12651  assert(conshdlr != NULL);
12652  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12653 
12654  /* call inclusion method of constraint handler */
12656 
12658 
12659  *valid = TRUE;
12660 
12661  return SCIP_OKAY;
12662 }
12663 
12664 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12665 static
12666 SCIP_DECL_CONSFREE(consFreeCumulative)
12667 { /*lint --e{715}*/
12668  SCIP_CONSHDLRDATA* conshdlrdata;
12669 
12670  assert(conshdlr != NULL);
12671  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12672 
12673  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12674  assert(conshdlrdata != NULL);
12675 
12676 #ifdef SCIP_STATISTIC
12677  if( !conshdlrdata->iscopy )
12678  {
12679  /* statisitc output if SCIP_STATISTIC is defined */
12680  SCIPstatisticPrintf("time-table: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12681  conshdlrdata->nlbtimetable, conshdlrdata->nubtimetable, conshdlrdata->ncutofftimetable);
12682  SCIPstatisticPrintf("edge-finder: lb=%" SCIP_LONGINT_FORMAT ", ub=%" SCIP_LONGINT_FORMAT ", cutoff=%" SCIP_LONGINT_FORMAT "\n",
12683  conshdlrdata->nlbedgefinder, conshdlrdata->nubedgefinder, conshdlrdata->ncutoffedgefinder);
12684  SCIPstatisticPrintf("overload: time-table=%" SCIP_LONGINT_FORMAT " time-time edge-finding=%" SCIP_LONGINT_FORMAT "\n",
12685  conshdlrdata->ncutoffoverload, conshdlrdata->ncutoffoverloadTTEF);
12686  }
12687 #endif
12688 
12689  conshdlrdataFree(scip, &conshdlrdata);
12690 
12691  SCIPconshdlrSetData(conshdlr, NULL);
12692 
12693  return SCIP_OKAY;
12694 }
12695 
12696 
12697 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12698 static
12699 SCIP_DECL_CONSINITPRE(consInitpreCumulative)
12700 { /*lint --e{715}*/
12701  SCIP_CONSHDLRDATA* conshdlrdata;
12702  int c;
12703 
12704  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12705  assert(conshdlrdata != NULL);
12706 
12707  conshdlrdata->detectedredundant = FALSE;
12708 
12709  for( c = 0; c < nconss; ++c )
12710  {
12711  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
12712  * hmax)
12713  */
12714  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
12715  }
12716 
12717  return SCIP_OKAY;
12718 }
12719 
12720 
12721 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12722 #ifdef SCIP_STATISTIC
12723 static
12724 SCIP_DECL_CONSEXITPRE(consExitpreCumulative)
12725 { /*lint --e{715}*/
12726  SCIP_CONSHDLRDATA* conshdlrdata;
12727  int c;
12728 
12729  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12730  assert(conshdlrdata != NULL);
12731 
12732  for( c = 0; c < nconss; ++c )
12733  {
12734  SCIP_CALL( evaluateCumulativeness(scip, conss[c]) );
12735 
12736 #if 0
12737  SCIP_CALL( SCIPvisualizeConsCumulative(scip, conss[c]) );
12738 #endif
12739  }
12740 
12741  if( !conshdlrdata->iscopy )
12742  {
12743  SCIPstatisticPrintf("@11 added variables bounds constraints %d\n", conshdlrdata->naddedvarbounds);
12744  SCIPstatisticPrintf("@22 added disjunctive constraints %d\n", conshdlrdata->naddeddisjunctives);
12745  SCIPstatisticPrintf("@33 irrelevant %d\n", conshdlrdata->nirrelevantjobs);
12746  SCIPstatisticPrintf("@44 dual %d\n", conshdlrdata->ndualfixs);
12747  SCIPstatisticPrintf("@55 locks %d\n", conshdlrdata->nremovedlocks);
12748  SCIPstatisticPrintf("@66 decomp %d\n", conshdlrdata->ndecomps);
12749  SCIPstatisticPrintf("@77 allconsdual %d\n", conshdlrdata->nallconsdualfixs);
12750  SCIPstatisticPrintf("@88 alwaysruns %d\n", conshdlrdata->nalwaysruns);
12751  SCIPstatisticPrintf("@99 dualbranch %d\n", conshdlrdata->ndualbranchs);
12752  }
12753 
12754  return SCIP_OKAY;
12755 }
12756 #endif
12757 
12758 
12759 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
12760 static
12761 SCIP_DECL_CONSEXITSOL(consExitsolCumulative)
12762 { /*lint --e{715}*/
12763  SCIP_CONSDATA* consdata;
12764  int c;
12765 
12766  assert(conshdlr != NULL);
12767  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12768 
12769  /* release the rows of all constraints */
12770  for( c = 0; c < nconss; ++c )
12771  {
12772  consdata = SCIPconsGetData(conss[c]);
12773  assert(consdata != NULL);
12774 
12775  /* free rows */
12776  SCIP_CALL( consdataFreeRows(scip, &consdata) );
12777  }
12778 
12779  return SCIP_OKAY;
12780 }
12781 
12782 /** frees specific constraint data */
12783 static
12784 SCIP_DECL_CONSDELETE(consDeleteCumulative)
12785 { /*lint --e{715}*/
12786  assert(conshdlr != NULL);
12787  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12788  assert(consdata != NULL );
12789  assert(*consdata != NULL );
12790 
12791  /* if constraint belongs to transformed problem space, drop bound change events on variables */
12792  if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
12793  {
12794  SCIP_CONSHDLRDATA* conshdlrdata;
12795 
12796  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12797  assert(conshdlrdata != NULL);
12798 
12799  SCIP_CALL( consdataDropAllEvents(scip, *consdata, conshdlrdata->eventhdlr) );
12800  }
12801 
12802  /* free cumulative constraint data */
12803  SCIP_CALL( consdataFree(scip, consdata) );
12804 
12805  return SCIP_OKAY;
12806 }
12807 
12808 /** transforms constraint data into data belonging to the transformed problem */
12809 static
12810 SCIP_DECL_CONSTRANS(consTransCumulative)
12811 { /*lint --e{715}*/
12812  SCIP_CONSHDLRDATA* conshdlrdata;
12813  SCIP_CONSDATA* sourcedata;
12814  SCIP_CONSDATA* targetdata;
12815 
12816  assert(conshdlr != NULL);
12817  assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
12818  assert(sourcecons != NULL);
12819  assert(targetcons != NULL);
12820 
12821  sourcedata = SCIPconsGetData(sourcecons);
12822  assert(sourcedata != NULL);
12823  assert(sourcedata->demandrows == NULL);
12824 
12825  SCIPdebugMsg(scip, "transform cumulative constraint <%s>\n", SCIPconsGetName(sourcecons));
12826 
12827  /* get event handler */
12828  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12829  assert(conshdlrdata != NULL);
12830  assert(conshdlrdata->eventhdlr != NULL);
12831 
12832  /* create constraint data for target constraint */
12833  SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->linkingconss,
12834  sourcedata->durations, sourcedata->demands, sourcedata->nvars, sourcedata->capacity,
12835  sourcedata->hmin, sourcedata->hmax, SCIPconsIsChecked(sourcecons)) );
12836 
12837  /* create target constraint */
12838  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12839  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12840  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
12841  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
12842  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
12843 
12844  /* catch bound change events of variables */
12845  SCIP_CALL( consdataCatchEvents(scip, targetdata, conshdlrdata->eventhdlr) );
12846 
12847  return SCIP_OKAY;
12848 }
12849 
12850 /** LP initialization method of constraint handler */
12851 static
12852 SCIP_DECL_CONSINITLP(consInitlpCumulative)
12854  SCIP_CONSHDLRDATA* conshdlrdata;
12855  int c;
12856 
12857  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12858  assert(conshdlr != NULL);
12859  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12860  assert(conshdlrdata != NULL);
12861 
12862  *infeasible = FALSE;
12863 
12864  SCIPdebugMsg(scip, "initialize LP relaxation for %d cumulative constraints\n", nconss);
12865 
12866  if( conshdlrdata->usebinvars )
12867  {
12868  /* add rows to LP */
12869  for( c = 0; c < nconss && !(*infeasible); ++c )
12870  {
12871  assert(SCIPconsIsInitial(conss[c]));
12872  SCIP_CALL( addRelaxation(scip, conss[c], conshdlrdata->cutsasconss, infeasible) );
12873 
12874  if( conshdlrdata->cutsasconss )
12875  {
12876  SCIP_CALL( SCIPrestartSolve(scip) );
12877  }
12878  }
12879  }
12880 
12881  /**@todo if we want to use only the integer variables; only these will be in cuts
12882  * create some initial cuts, currently these are only separated */
12883 
12884  return SCIP_OKAY;
12885 }
12886 
12887 /** separation method of constraint handler for LP solutions */
12888 static
12889 SCIP_DECL_CONSSEPALP(consSepalpCumulative)
12891  SCIP_CONSHDLRDATA* conshdlrdata;
12892  SCIP_Bool cutoff;
12893  SCIP_Bool separated;
12894  int c;
12895 
12896  SCIPdebugMsg(scip, "consSepalpCumulative\n");
12897 
12898  assert(conshdlr != NULL);
12899  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12900  assert(nconss == 0 || conss != NULL);
12901  assert(result != NULL);
12902  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12903  assert(conshdlrdata != NULL);
12904 
12905  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12906 
12907  cutoff = FALSE;
12908  separated = FALSE;
12909  (*result) = SCIP_DIDNOTRUN;
12910 
12911  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12912  return SCIP_OKAY;
12913 
12914  (*result) = SCIP_DIDNOTFIND;
12915 
12916  if( conshdlrdata->usebinvars )
12917  {
12918  /* check all useful cumulative constraints for feasibility */
12919  for( c = 0; c < nusefulconss && !cutoff; ++c )
12920  {
12921  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12922  }
12923 
12924  if( !cutoff && conshdlrdata->usecovercuts )
12925  {
12926  for( c = 0; c < nusefulconss; ++c )
12927  {
12928  SCIP_CALL( separateCoverCutsCons(scip, conss[c], NULL, &separated, &cutoff) );
12929  }
12930  }
12931  }
12932 
12933  if( conshdlrdata->sepaold )
12934  {
12935  /* separate cuts containing only integer variables */
12936  for( c = 0; c < nusefulconss; ++c )
12937  {
12938  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12939  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
12940  }
12941  }
12942 
12943  if( cutoff )
12944  *result = SCIP_CUTOFF;
12945  else if( separated )
12946  *result = SCIP_SEPARATED;
12947 
12948  return SCIP_OKAY;
12949 }
12950 
12951 /** separation method of constraint handler for arbitrary primal solutions */
12952 static
12953 SCIP_DECL_CONSSEPASOL(consSepasolCumulative)
12954 { /*lint --e{715}*/
12955  SCIP_CONSHDLRDATA* conshdlrdata;
12956  SCIP_Bool cutoff;
12957  SCIP_Bool separated;
12958  int c;
12959 
12960  assert(conshdlr != NULL);
12961  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12962  assert(nconss == 0 || conss != NULL);
12963  assert(result != NULL);
12964 
12965  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12966  assert(conshdlrdata != NULL);
12967 
12968  if( !conshdlrdata->localcuts && SCIPgetDepth(scip) > 0 )
12969  return SCIP_OKAY;
12970 
12971  SCIPdebugMsg(scip, "separating %d/%d cumulative constraints\n", nusefulconss, nconss);
12972 
12973  cutoff = FALSE;
12974  separated = FALSE;
12975  (*result) = SCIP_DIDNOTFIND;
12976 
12977  if( conshdlrdata->usebinvars )
12978  {
12979  /* check all useful cumulative constraints for feasibility */
12980  for( c = 0; c < nusefulconss && !cutoff; ++c )
12981  {
12982  SCIP_CALL( separateConsBinaryRepresentation(scip, conss[c], NULL, &separated, &cutoff) );
12983  }
12984 
12985  if( !cutoff && conshdlrdata->usecovercuts )
12986  {
12987  for( c = 0; c < nusefulconss; ++c )
12988  {
12989  SCIP_CALL( separateCoverCutsCons(scip, conss[c], sol, &separated, &cutoff) );
12990  }
12991  }
12992  }
12993  if( conshdlrdata->sepaold )
12994  {
12995  /* separate cuts containing only integer variables */
12996  for( c = 0; c < nusefulconss; ++c )
12997  {
12998  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, TRUE, &separated, &cutoff) );
12999  SCIP_CALL( separateConsOnIntegerVariables(scip, conss[c], NULL, FALSE, &separated, &cutoff) );
13000  }
13001  }
13002 
13003  if( cutoff )
13004  *result = SCIP_CUTOFF;
13005  else if( separated )
13006  *result = SCIP_SEPARATED;
13007 
13008  return SCIP_OKAY;
13009 }
13010 
13011 /** constraint enforcing method of constraint handler for LP solutions */
13012 static
13013 SCIP_DECL_CONSENFOLP(consEnfolpCumulative)
13014 { /*lint --e{715}*/
13015  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
13016 
13017  return SCIP_OKAY;
13018 }
13019 
13020 /** constraint enforcing method of constraint handler for relaxation solutions */
13021 static
13022 SCIP_DECL_CONSENFORELAX(consEnforelaxCumulative)
13023 { /*lint --e{715}*/
13024  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
13025 
13026  return SCIP_OKAY;
13027 }
13028 
13029 /** constraint enforcing method of constraint handler for pseudo solutions */
13030 static
13031 SCIP_DECL_CONSENFOPS(consEnfopsCumulative)
13032 { /*lint --e{715}*/
13033  SCIP_CONSHDLRDATA* conshdlrdata;
13034 
13035  SCIPdebugMsg(scip, "method: enforce pseudo solution\n");
13036 
13037  assert(conshdlr != NULL);
13038  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13039  assert(nconss == 0 || conss != NULL);
13040  assert(result != NULL);
13041 
13042  if( objinfeasible )
13043  {
13044  *result = SCIP_DIDNOTRUN;
13045  return SCIP_OKAY;
13046  }
13047 
13048  (*result) = SCIP_FEASIBLE;
13049 
13050  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13051  assert(conshdlrdata != NULL);
13052 
13053  SCIP_CALL( enforceSolution(scip, conss, nconss, NULL, conshdlrdata->fillbranchcands, result) );
13054 
13055  return SCIP_OKAY;
13056 }
13057 
13058 /** feasibility check method of constraint handler for integral solutions */
13059 static
13060 SCIP_DECL_CONSCHECK(consCheckCumulative)
13061 { /*lint --e{715}*/
13062  int c;
13063 
13064  assert(conshdlr != NULL);
13065  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13066  assert(nconss == 0 || conss != NULL);
13067  assert(result != NULL);
13068 
13069  *result = SCIP_FEASIBLE;
13070 
13071  SCIPdebugMsg(scip, "check %d cumulative constraints\n", nconss);
13072 
13073  for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
13074  {
13075  SCIP_Bool violated = FALSE;
13076 
13077  SCIP_CALL( checkCons(scip, conss[c], sol, &violated, printreason) );
13078 
13079  if( violated )
13080  *result = SCIP_INFEASIBLE;
13081  }
13082 
13083  return SCIP_OKAY;
13084 }
13085 
13086 /** domain propagation method of constraint handler */
13087 static
13088 SCIP_DECL_CONSPROP(consPropCumulative)
13089 { /*lint --e{715}*/
13090  SCIP_CONSHDLRDATA* conshdlrdata;
13091  SCIP_Bool cutoff;
13092  int nchgbds;
13093  int ndelconss;
13094  int c;
13095 #if 0
13096  int naggrvars = 0;
13097 #endif
13098 
13099  SCIPdebugMsg(scip, "propagate %d of %d useful cumulative constraints\n", nusefulconss, nconss);
13100 
13101  assert(conshdlr != NULL);
13102  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13103  assert(nconss == 0 || conss != NULL);
13104  assert(result != NULL);
13105 
13106  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13107  assert(conshdlrdata != NULL);
13108 
13109  nchgbds = 0;
13110  ndelconss = 0;
13111  cutoff = FALSE;
13112  (*result) = SCIP_DIDNOTRUN;
13113 
13114  /* propgate all useful constraints */
13115  for( c = 0; c < nusefulconss && !cutoff; ++c )
13116  {
13117  SCIP_CONS* cons;
13118 
13119  cons = conss[c];
13120  assert(cons != NULL);
13121 
13122  if( SCIPgetDepth(scip) == 0 )
13123  {
13124 #if 0
13125  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13126  &nchgbds, &naggrvars, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13127 #else
13128  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS,
13129  &nchgbds, &nchgbds, &ndelconss, &nchgbds, &nchgbds, &nchgbds, &cutoff, &cutoff) );
13130 #endif
13131  if( cutoff )
13132  break;
13133 
13134  if( SCIPconsIsDeleted(cons) )
13135  continue;
13136  }
13137 
13138  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13139  }
13140 
13141  if( !cutoff && nchgbds == 0 )
13142  {
13143  /* propgate all other constraints */
13144  for( c = nusefulconss; c < nconss && !cutoff; ++c )
13145  {
13146  SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata, SCIP_PRESOLTIMING_ALWAYS, &nchgbds, &ndelconss, &cutoff) );
13147  }
13148  }
13149 
13150 #if 0
13151  if( !cutoff && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 )
13152  {
13153  SCIP_CALL( propagateAllConss(scip, conss, nconss, TRUE, &nchgbds, &cutoff, NULL) );
13154  }
13155 #endif
13156 
13157  if( cutoff )
13158  {
13159  SCIPdebugMsg(scip, "detected infeasible\n");
13160  *result = SCIP_CUTOFF;
13161  }
13162  else if( nchgbds > 0 )
13163  {
13164  SCIPdebugMsg(scip, "delete (locally) %d constraints and changed %d variable bounds\n", ndelconss, nchgbds);
13165  *result = SCIP_REDUCEDDOM;
13166  }
13167  else
13168  *result = SCIP_DIDNOTFIND;
13169 
13170  return SCIP_OKAY;
13171 }
13172 
13173 /** presolving method of constraint handler */
13174 static
13175 SCIP_DECL_CONSPRESOL(consPresolCumulative)
13176 { /*lint --e{715}*/
13177  SCIP_CONSHDLRDATA* conshdlrdata;
13178  SCIP_CONS* cons;
13179  SCIP_Bool cutoff;
13180  SCIP_Bool unbounded;
13181  int oldnfixedvars;
13182  int oldnchgbds;
13183  int oldndelconss;
13184  int oldnaddconss;
13185  int oldnupgdconss;
13186  int oldnchgsides;
13187  int oldnchgcoefs;
13188  int c;
13189 
13190  assert(conshdlr != NULL);
13191  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13192  assert(scip != NULL);
13193  assert(result != NULL);
13194 
13195  SCIPdebugMsg(scip, "presolve %d cumulative constraints\n", nconss);
13196 
13197  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13198  assert(conshdlrdata != NULL);
13199 
13200  *result = SCIP_DIDNOTRUN;
13201 
13202  oldnfixedvars = *nfixedvars;
13203  oldnchgbds = *nchgbds;
13204  oldnchgsides = *nchgsides;
13205  oldnchgcoefs = *nchgcoefs;
13206  oldnupgdconss = *nupgdconss;
13207  oldndelconss = *ndelconss;
13208  oldnaddconss = *naddconss;
13209  cutoff = FALSE;
13210  unbounded = FALSE;
13211 
13212  /* process constraints */
13213  for( c = 0; c < nconss && !cutoff; ++c )
13214  {
13215  cons = conss[c];
13216 
13217  /* remove jobs which have a duration or demand of zero (zero energy) or lay outside the effective horizon [hmin,
13218  * hmax)
13219  */
13220  SCIP_CALL( removeIrrelevantJobs(scip, conss[c]) );
13221 
13222  if( presoltiming != SCIP_PRESOLTIMING_MEDIUM )
13223  {
13224 #if 0
13225  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13226  nfixedvars, naggrvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13227 #else
13228  SCIP_CALL( presolveCons(scip, cons, conshdlrdata, presoltiming,
13229  nfixedvars, nchgbds, ndelconss, naddconss, nchgcoefs, nchgsides, &cutoff, &unbounded) );
13230 #endif
13231 
13232  if( cutoff || unbounded )
13233  break;
13234 
13235  if( SCIPconsIsDeleted(cons) )
13236  continue;
13237  }
13238 
13239  /* in the first round we create a disjunctive constraint containing those jobs which cannot run in parallel */
13240  if( nrounds == 1 && SCIPgetNRuns(scip) == 1 && conshdlrdata->disjunctive )
13241  {
13242  SCIP_CALL( createDisjuctiveCons(scip, cons, naddconss) );
13243  }
13244 
13245  /* strengthen existing variable bounds using the cumulative condition */
13246  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13247  {
13248  SCIP_CALL( strengthenVarbounds(scip, cons, nchgbds, naddconss) );
13249  }
13250 
13251  /* propagate cumulative constraint */
13252  SCIP_CALL( propagateCons(scip, cons, conshdlrdata, presoltiming, nchgbds, ndelconss, &cutoff) );
13253  assert(checkDemands(scip, cons) || cutoff);
13254  }
13255 
13256  if( !cutoff && !unbounded && conshdlrdata->dualpresolve && SCIPallowStrongDualReds(scip) && nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13257  {
13258  SCIP_CALL( propagateAllConss(scip, conss, nconss, FALSE, nfixedvars, &cutoff, NULL) );
13259  }
13260 
13261  /* only perform the detection of variable bounds and disjunctive constraint once */
13262  if( !cutoff && SCIPgetNRuns(scip) == 1 && !conshdlrdata->detectedredundant
13263  && (conshdlrdata->detectvarbounds || conshdlrdata->detectdisjunctive)
13264  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
13265  {
13266  /* combine different source and detect disjunctive constraints and variable bound constraints to improve the
13267  * propagation
13268  */
13269  SCIP_CALL( detectRedundantConss(scip, conshdlrdata, conss, nconss, naddconss) );
13270  conshdlrdata->detectedredundant = TRUE;
13271  }
13272 
13273  if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
13274  {
13275  SCIP_CALL( removeRedundantConss(scip, conss, nconss, ndelconss) );
13276  }
13277 
13278  SCIPdebugMsg(scip, "delete %d constraints and changed %d variable bounds (cutoff %u)\n",
13279  *ndelconss - oldndelconss, *nchgbds - oldnchgbds, cutoff);
13280 
13281  if( cutoff )
13282  *result = SCIP_CUTOFF;
13283  else if( unbounded )
13284  *result = SCIP_UNBOUNDED;
13285  else if( *nchgbds > oldnchgbds || *nfixedvars > oldnfixedvars || *nchgsides > oldnchgsides
13286  || *nchgcoefs > oldnchgcoefs || *nupgdconss > oldnupgdconss || *ndelconss > oldndelconss || *naddconss > oldnaddconss )
13287  *result = SCIP_SUCCESS;
13288  else
13289  *result = SCIP_DIDNOTFIND;
13290 
13291  return SCIP_OKAY;
13292 }
13293 
13294 /** propagation conflict resolving method of constraint handler */
13295 static
13296 SCIP_DECL_CONSRESPROP(consRespropCumulative)
13297 { /*lint --e{715}*/
13298  SCIP_CONSHDLRDATA* conshdlrdata;
13299  SCIP_CONSDATA* consdata;
13300 
13301  assert(conshdlr != NULL);
13302  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13303  assert(scip != NULL);
13304  assert(result != NULL);
13305  assert(infervar != NULL);
13306  assert(bdchgidx != NULL);
13307 
13308  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13309  assert(conshdlrdata != NULL);
13310 
13311  /* process constraint */
13312  assert(cons != NULL);
13313 
13314  consdata = SCIPconsGetData(cons);
13315  assert(consdata != NULL);
13316 
13317  SCIPdebugMsg(scip, "resolve propagation: variable <%s>, cumulative constraint <%s> (capacity %d, propagation %d, H=[%d,%d))\n",
13318  SCIPvarGetName(infervar), SCIPconsGetName(cons), consdata->capacity, inferInfoGetProprule(intToInferInfo(inferinfo)),
13319  SCIPgetHminCumulative(scip, cons), SCIPgetHmaxCumulative(scip, cons));
13320 
13321  SCIP_CALL( respropCumulativeCondition(scip, consdata->nvars, consdata->vars,
13322  consdata->durations, consdata->demands, consdata->capacity, consdata->hmin, consdata->hmax,
13323  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, conshdlrdata->usebdwidening, NULL, result) );
13324 
13325  return SCIP_OKAY;
13326 }
13327 
13328 /** variable rounding lock method of constraint handler */
13329 static
13330 SCIP_DECL_CONSLOCK(consLockCumulative)
13331 { /*lint --e{715}*/
13332  SCIP_CONSDATA* consdata;
13333  SCIP_VAR** vars;
13334  int v;
13335 
13336  SCIPdebugMsg(scip, "lock cumulative constraint <%s> with nlockspos = %d, nlocksneg = %d\n", SCIPconsGetName(cons), nlockspos, nlocksneg);
13337 
13338  assert(scip != NULL);
13339  assert(cons != NULL);
13340  assert(locktype == SCIP_LOCKTYPE_MODEL);
13341 
13342  consdata = SCIPconsGetData(cons);
13343  assert(consdata != NULL);
13344 
13345  vars = consdata->vars;
13346  assert(vars != NULL);
13347 
13348  for( v = 0; v < consdata->nvars; ++v )
13349  {
13350  if( consdata->downlocks[v] && consdata->uplocks[v] )
13351  {
13352  /* the integer start variable should not get rounded in both direction */
13353  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
13354  }
13355  else if( consdata->downlocks[v] )
13356  {
13357  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlockspos, nlocksneg) );
13358  }
13359  else if( consdata->uplocks[v] )
13360  {
13361  SCIP_CALL( SCIPaddVarLocksType(scip, vars[v], locktype, nlocksneg, nlockspos) );
13362  }
13363  }
13364 
13365  return SCIP_OKAY;
13366 }
13367 
13368 
13369 /** constraint display method of constraint handler */
13370 static
13371 SCIP_DECL_CONSPRINT(consPrintCumulative)
13372 { /*lint --e{715}*/
13373  assert(scip != NULL);
13374  assert(conshdlr != NULL);
13375  assert(cons != NULL);
13376 
13377  consdataPrint(scip, SCIPconsGetData(cons), file);
13378 
13379  return SCIP_OKAY;
13380 }
13381 
13382 /** constraint copying method of constraint handler */
13383 static
13384 SCIP_DECL_CONSCOPY(consCopyCumulative)
13385 { /*lint --e{715}*/
13386  SCIP_CONSDATA* sourceconsdata;
13387  SCIP_VAR** sourcevars;
13388  SCIP_VAR** vars;
13389  const char* consname;
13390 
13391  int nvars;
13392  int v;
13393 
13394  sourceconsdata = SCIPconsGetData(sourcecons);
13395  assert(sourceconsdata != NULL);
13396 
13397  /* get variables of the source constraint */
13398  nvars = sourceconsdata->nvars;
13399  sourcevars = sourceconsdata->vars;
13400 
13401  (*valid) = TRUE;
13402 
13403  if( nvars == 0 )
13404  return SCIP_OKAY;
13405 
13406  /* allocate buffer array */
13407  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
13408 
13409  for( v = 0; v < nvars && *valid; ++v )
13410  {
13411  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
13412  assert(!(*valid) || vars[v] != NULL);
13413  }
13414 
13415  /* only create the target constraint, if all variables could be copied */
13416  if( *valid )
13417  {
13418  if( name != NULL )
13419  consname = name;
13420  else
13421  consname = SCIPconsGetName(sourcecons);
13422 
13423  /* create a copy of the cumulative constraint */
13424  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, consname, nvars, vars,
13425  sourceconsdata->durations, sourceconsdata->demands, sourceconsdata->capacity,
13426  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13427 
13428  /* adjust left side if the time axis if needed */
13429  if( sourceconsdata->hmin > 0 )
13430  {
13431  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, sourceconsdata->hmin) );
13432  }
13433 
13434  /* adjust right side if the time axis if needed */
13435  if( sourceconsdata->hmax < INT_MAX )
13436  {
13437  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, sourceconsdata->hmax) );
13438  }
13439  }
13440 
13441  /* free buffer array */
13442  SCIPfreeBufferArray(scip, &vars);
13443 
13444  return SCIP_OKAY;
13445 }
13446 
13447 
13448 /** constraint parsing method of constraint handler */
13449 static
13450 SCIP_DECL_CONSPARSE(consParseCumulative)
13451 { /*lint --e{715}*/
13452  SCIP_VAR** vars;
13453  SCIP_VAR* var;
13454  SCIP_Real value;
13455  char strvalue[SCIP_MAXSTRLEN];
13456  char* endptr;
13457  int* demands;
13458  int* durations;
13459  int capacity;
13460  int duration;
13461  int demand;
13462  int hmin;
13463  int hmax;
13464  int varssize;
13465  int nvars;
13466 
13467  SCIPdebugMsg(scip, "parse <%s> as cumulative constraint\n", str);
13468 
13469  *success = TRUE;
13470 
13471  /* cutoff "cumulative" form the constraint string */
13472  SCIPstrCopySection(str, 'c', '(', strvalue, SCIP_MAXSTRLEN, &endptr);
13473  str = endptr;
13474 
13475  varssize = 100;
13476  nvars = 0;
13477 
13478  /* allocate buffer array for variables */
13479  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
13480  SCIP_CALL( SCIPallocBufferArray(scip, &demands, varssize) );
13481  SCIP_CALL( SCIPallocBufferArray(scip, &durations, varssize) );
13482 
13483  do
13484  {
13485  SCIP_CALL( SCIPparseVarName(scip, str, &var, &endptr) );
13486 
13487  if( var == NULL )
13488  {
13489  endptr = strchr(endptr, ')');
13490 
13491  if( endptr == NULL )
13492  *success = FALSE;
13493  else
13494  str = endptr;
13495 
13496  break;
13497  }
13498 
13499  str = endptr;
13500  SCIPstrCopySection(str, '(', ')', strvalue, SCIP_MAXSTRLEN, &endptr);
13501  duration = atoi(strvalue);
13502  str = endptr;
13503 
13504  SCIPstrCopySection(str, '[', ']', strvalue, SCIP_MAXSTRLEN, &endptr);
13505  demand = atoi(strvalue);
13506  str = endptr;
13507 
13508  SCIPdebugMsg(scip, "parse job <%s>, duration %d, demand %d\n", SCIPvarGetName(var), duration, demand);
13509 
13510  vars[nvars] = var;
13511  demands[nvars] = demand;
13512  durations[nvars] = duration;
13513  nvars++;
13514  }
13515  while( *str != ')' );
13516 
13517  if( *success )
13518  {
13519  /* parse effective time window */
13520  SCIPstrCopySection(str, '[', ',', strvalue, SCIP_MAXSTRLEN, &endptr);
13521  hmin = atoi(strvalue);
13522  str = endptr;
13523 
13524  if( SCIPparseReal(scip, str, &value, &endptr) )
13525  {
13526  hmax = (int)(value);
13527  str = endptr;
13528 
13529  /* parse capacity */
13530  SCIPstrCopySection(str, ')', '=', strvalue, SCIP_MAXSTRLEN, &endptr);
13531  str = endptr;
13532  if( SCIPparseReal(scip, str, &value, &endptr) )
13533  {
13534  capacity = (int)value;
13535 
13536  /* create cumulative constraint */
13537  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13538  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
13539 
13540  SCIP_CALL( SCIPsetHminCumulative(scip, *cons, hmin) );
13541  SCIP_CALL( SCIPsetHmaxCumulative(scip, *cons, hmax) );
13542  }
13543  }
13544  }
13545 
13546  /* free buffer arrays */
13547  SCIPfreeBufferArray(scip, &durations);
13548  SCIPfreeBufferArray(scip, &demands);
13549  SCIPfreeBufferArray(scip, &vars);
13550 
13551  return SCIP_OKAY;
13552 }
13553 
13554 
13555 /** constraint method of constraint handler which returns the variables (if possible) */
13556 static
13557 SCIP_DECL_CONSGETVARS(consGetVarsCumulative)
13558 { /*lint --e{715}*/
13559  SCIP_CONSDATA* consdata;
13560 
13561  consdata = SCIPconsGetData(cons);
13562  assert(consdata != NULL);
13563 
13564  if( varssize < consdata->nvars )
13565  (*success) = FALSE;
13566  else
13567  {
13568  assert(vars != NULL);
13569 
13570  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
13571  (*success) = TRUE;
13572  }
13573 
13574  return SCIP_OKAY;
13575 }
13576 
13577 /** constraint method of constraint handler which returns the number of variables (if possible) */
13578 static
13579 SCIP_DECL_CONSGETNVARS(consGetNVarsCumulative)
13580 { /*lint --e{715}*/
13581  SCIP_CONSDATA* consdata;
13582 
13583  consdata = SCIPconsGetData(cons);
13584  assert(consdata != NULL);
13585 
13586  (*nvars) = consdata->nvars;
13587  (*success) = TRUE;
13588 
13589  return SCIP_OKAY;
13590 }
13591 
13592 /**@} */
13593 
13594 /**@name Callback methods of event handler
13595  *
13596  * @{
13597  */
13598 
13599 
13600 /** execution method of event handler */
13601 static
13602 SCIP_DECL_EVENTEXEC(eventExecCumulative)
13603 { /*lint --e{715}*/
13604  SCIP_CONSDATA* consdata;
13605 
13606  assert(scip != NULL);
13607  assert(eventhdlr != NULL);
13608  assert(eventdata != NULL);
13609  assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
13610  assert(event != NULL);
13611 
13612  consdata = (SCIP_CONSDATA*)eventdata;
13613  assert(consdata != NULL);
13614 
13615  /* mark the constraint to be not propagated */
13616  consdata->propagated = FALSE;
13617 
13618  return SCIP_OKAY;
13619 }
13620 
13621 /**@} */
13622 
13623 /*
13624  * constraint specific interface methods
13625  */
13626 
13627 /** creates the handler for cumulative constraints and includes it in SCIP */
13629  SCIP* scip /**< SCIP data structure */
13630  )
13631 {
13632  SCIP_CONSHDLRDATA* conshdlrdata;
13633  SCIP_CONSHDLR* conshdlr;
13634  SCIP_EVENTHDLR* eventhdlr;
13635 
13636  /* create event handler for bound change events */
13637  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecCumulative, NULL) );
13638 
13639  /* create cumulative constraint handler data */
13640  SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
13641 
13642  /* include constraint handler */
13645  consEnfolpCumulative, consEnfopsCumulative, consCheckCumulative, consLockCumulative,
13646  conshdlrdata) );
13647 
13648  assert(conshdlr != NULL);
13649 
13650  /* set non-fundamental callbacks via specific setter functions */
13651  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCumulative, consCopyCumulative) );
13652  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCumulative) );
13653 #ifdef SCIP_STATISTIC
13654  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreCumulative) );
13655 #endif
13656  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCumulative) );
13657  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCumulative) );
13658  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCumulative) );
13659  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCumulative) );
13660  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreCumulative) );
13661  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCumulative) );
13662  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCumulative) );
13663  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolCumulative, CONSHDLR_MAXPREROUNDS,
13665  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCumulative) );
13666  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropCumulative, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13668  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCumulative) );
13669  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCumulative, consSepasolCumulative, CONSHDLR_SEPAFREQ,
13671  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCumulative) );
13672  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCumulative) );
13673 
13674  /* add cumulative constraint handler parameters */
13676  "constraints/" CONSHDLR_NAME "/ttinfer",
13677  "should time-table (core-times) propagator be used to infer bounds?",
13678  &conshdlrdata->ttinfer, FALSE, DEFAULT_TTINFER, NULL, NULL) );
13680  "constraints/" CONSHDLR_NAME "/efcheck",
13681  "should edge-finding be used to detect an overload?",
13682  &conshdlrdata->efcheck, FALSE, DEFAULT_EFCHECK, NULL, NULL) );
13684  "constraints/" CONSHDLR_NAME "/efinfer",
13685  "should edge-finding be used to infer bounds?",
13686  &conshdlrdata->efinfer, FALSE, DEFAULT_EFINFER, NULL, NULL) );
13688  "constraints/" CONSHDLR_NAME "/useadjustedjobs", "should edge-finding be executed?",
13689  &conshdlrdata->useadjustedjobs, TRUE, DEFAULT_USEADJUSTEDJOBS, NULL, NULL) );
13691  "constraints/" CONSHDLR_NAME "/ttefcheck",
13692  "should time-table edge-finding be used to detect an overload?",
13693  &conshdlrdata->ttefcheck, FALSE, DEFAULT_TTEFCHECK, NULL, NULL) );
13695  "constraints/" CONSHDLR_NAME "/ttefinfer",
13696  "should time-table edge-finding be used to infer bounds?",
13697  &conshdlrdata->ttefinfer, FALSE, DEFAULT_TTEFINFER, NULL, NULL) );
13698 
13700  "constraints/" CONSHDLR_NAME "/usebinvars", "should the binary representation be used?",
13701  &conshdlrdata->usebinvars, FALSE, DEFAULT_USEBINVARS, NULL, NULL) );
13703  "constraints/" CONSHDLR_NAME "/localcuts", "should cuts be added only locally?",
13704  &conshdlrdata->localcuts, FALSE, DEFAULT_LOCALCUTS, NULL, NULL) );
13706  "constraints/" CONSHDLR_NAME "/usecovercuts", "should covering cuts be added every node?",
13707  &conshdlrdata->usecovercuts, FALSE, DEFAULT_USECOVERCUTS, NULL, NULL) );
13709  "constraints/" CONSHDLR_NAME "/cutsasconss",
13710  "should the cumulative constraint create cuts as knapsack constraints?",
13711  &conshdlrdata->cutsasconss, FALSE, DEFAULT_CUTSASCONSS, NULL, NULL) );
13713  "constraints/" CONSHDLR_NAME "/sepaold",
13714  "shall old sepa algo be applied?",
13715  &conshdlrdata->sepaold, FALSE, DEFAULT_SEPAOLD, NULL, NULL) );
13716 
13718  "constraints/" CONSHDLR_NAME "/fillbranchcands", "should branching candidates be added to storage?",
13719  &conshdlrdata->fillbranchcands, FALSE, DEFAULT_FILLBRANCHCANDS, NULL, NULL) );
13720 
13721  /* presolving parameters */
13723  "constraints/" CONSHDLR_NAME "/dualpresolve", "should dual presolving be applied?",
13724  &conshdlrdata->dualpresolve, FALSE, DEFAULT_DUALPRESOLVE, NULL, NULL) );
13726  "constraints/" CONSHDLR_NAME "/coeftightening", "should coefficient tightening be applied?",
13727  &conshdlrdata->coeftightening, FALSE, DEFAULT_COEFTIGHTENING, NULL, NULL) );
13729  "constraints/" CONSHDLR_NAME "/normalize", "should demands and capacity be normalized?",
13730  &conshdlrdata->normalize, FALSE, DEFAULT_NORMALIZE, NULL, NULL) );
13732  "constraints/" CONSHDLR_NAME "/presolpairwise",
13733  "should pairwise constraint comparison be performed in presolving?",
13734  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
13736  "constraints/" CONSHDLR_NAME "/disjunctive", "extract disjunctive constraints?",
13737  &conshdlrdata->disjunctive, FALSE, DEFAULT_DISJUNCTIVE, NULL, NULL) );
13738 
13740  "constraints/" CONSHDLR_NAME "/maxnodes",
13741  "number of branch-and-bound nodes to solve an independent cumulative constraint (-1: no limit)?",
13742  &conshdlrdata->maxnodes, FALSE, DEFAULT_MAXNODES, -1LL, SCIP_LONGINT_MAX, NULL, NULL) );
13744  "constraints/" CONSHDLR_NAME "/detectdisjunctive", "search for conflict set via maximal cliques to detect disjunctive constraints",
13745  &conshdlrdata->detectdisjunctive, FALSE, DEFAULT_DETECTDISJUNCTIVE, NULL, NULL) );
13747  "constraints/" CONSHDLR_NAME "/detectvarbounds", "search for conflict set via maximal cliques to detect variable bound constraints",
13748  &conshdlrdata->detectvarbounds, FALSE, DEFAULT_DETECTVARBOUNDS, NULL, NULL) );
13749 
13750  /* conflict analysis parameters */
13752  "constraints/" CONSHDLR_NAME "/usebdwidening", "should bound widening be used during the conflict analysis?",
13753  &conshdlrdata->usebdwidening, FALSE, DEFAULT_USEBDWIDENING, NULL, NULL) );
13754 
13755  return SCIP_OKAY;
13756 }
13757 
13758 /** creates and captures a cumulative constraint */
13760  SCIP* scip, /**< SCIP data structure */
13761  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13762  const char* name, /**< name of constraint */
13763  int nvars, /**< number of variables (jobs) */
13764  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13765  int* durations, /**< array containing corresponding durations */
13766  int* demands, /**< array containing corresponding demands */
13767  int capacity, /**< available cumulative capacity */
13768  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13769  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13770  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13771  * Usually set to TRUE. */
13772  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13773  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13774  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13775  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13776  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13777  * Usually set to TRUE. */
13778  SCIP_Bool local, /**< is constraint only valid locally?
13779  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13780  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13781  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13782  * adds coefficients to this constraint. */
13783  SCIP_Bool dynamic, /**< is constraint subject to aging?
13784  * Usually set to FALSE. Set to TRUE for own cuts which
13785  * are seperated as constraints. */
13786  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
13787  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13788  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
13789  * if it may be moved to a more global node?
13790  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
13791  )
13792 {
13793  SCIP_CONSHDLR* conshdlr;
13794  SCIP_CONSDATA* consdata;
13795 
13796  assert(scip != NULL);
13797 
13798  /* find the cumulative constraint handler */
13799  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13800  if( conshdlr == NULL )
13801  {
13802  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
13803  return SCIP_PLUGINNOTFOUND;
13804  }
13805 
13806  SCIPdebugMsg(scip, "create cumulative constraint <%s> with %d jobs\n", name, nvars);
13807 
13808  /* create constraint data */
13809  SCIP_CALL( consdataCreate(scip, &consdata, vars, NULL, durations, demands, nvars, capacity, 0, INT_MAX, check) );
13810 
13811  /* create constraint */
13812  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata,
13813  initial, separate, enforce, check, propagate,
13814  local, modifiable, dynamic, removable, stickingatnode) );
13815 
13816  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13817  {
13818  SCIP_CONSHDLRDATA* conshdlrdata;
13819 
13820  /* get event handler */
13821  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13822  assert(conshdlrdata != NULL);
13823  assert(conshdlrdata->eventhdlr != NULL);
13824 
13825  /* catch bound change events of variables */
13826  SCIP_CALL( consdataCatchEvents(scip, consdata, conshdlrdata->eventhdlr) );
13827  }
13828 
13829  return SCIP_OKAY;
13830 }
13831 
13832 /** creates and captures a cumulative constraint
13833  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
13834  * method SCIPcreateConsCumulative(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
13835  *
13836  * @see SCIPcreateConsCumulative() for information about the basic constraint flag configuration
13837  *
13838  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13839  */
13841  SCIP* scip, /**< SCIP data structure */
13842  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13843  const char* name, /**< name of constraint */
13844  int nvars, /**< number of variables (jobs) */
13845  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
13846  int* durations, /**< array containing corresponding durations */
13847  int* demands, /**< array containing corresponding demands */
13848  int capacity /**< available cumulative capacity */
13849  )
13850 {
13851  assert(scip != NULL);
13852 
13853  SCIP_CALL( SCIPcreateConsCumulative(scip, cons, name, nvars, vars, durations, demands, capacity,
13854  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13855 
13856  return SCIP_OKAY;
13857 }
13858 
13859 /** set the left bound of the time axis to be considered (including hmin) */ /*lint -e{715}*/
13861  SCIP* scip, /**< SCIP data structure */
13862  SCIP_CONS* cons, /**< constraint data */
13863  int hmin /**< left bound of time axis to be considered */
13864  )
13865 {
13866  SCIP_CONSDATA* consdata;
13867  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13868  {
13869  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13870  return SCIP_INVALIDCALL;
13871  }
13872 
13873  consdata = SCIPconsGetData(cons);
13874  assert(consdata != NULL);
13875  assert(hmin >= 0);
13876  assert(hmin <= consdata->hmax);
13877 
13878  consdata->hmin = hmin;
13879 
13880  return SCIP_OKAY;
13881 }
13882 
13883 /** returns the left bound of the time axis to be considered */ /*lint -e{715}*/
13885  SCIP* scip, /**< SCIP data structure */
13886  SCIP_CONS* cons /**< constraint */
13887  )
13888 {
13889  SCIP_CONSDATA* consdata;
13890  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13891  {
13892  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13893  SCIPABORT();
13894  return 0; /*lint !e527*/
13895  }
13896 
13897  consdata = SCIPconsGetData(cons);
13898  assert(consdata != NULL);
13899 
13900  return consdata->hmin;
13901 }
13902 
13903 /** set the right bound of the time axis to be considered (not including hmax) */ /*lint -e{715}*/
13905  SCIP* scip, /**< SCIP data structure */
13906  SCIP_CONS* cons, /**< constraint data */
13907  int hmax /**< right bound of time axis to be considered */
13908  )
13909 {
13910  SCIP_CONSDATA* consdata;
13911  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13912  {
13913  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13914  SCIPABORT();
13915  return SCIP_INVALIDCALL; /*lint !e527*/
13916  }
13917 
13918  consdata = SCIPconsGetData(cons);
13919  assert(consdata != NULL);
13920  assert(hmax >= consdata->hmin);
13921 
13922  consdata->hmax = hmax;
13923 
13924  return SCIP_OKAY;
13925 }
13926 
13927 /** returns the right bound of the time axis to be considered */ /*lint -e{715}*/
13929  SCIP* scip, /**< SCIP data structure */
13930  SCIP_CONS* cons /**< constraint */
13931  )
13932 {
13933  SCIP_CONSDATA* consdata;
13934  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13935  {
13936  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13937  SCIPABORT();
13938  return 0; /*lint !e527*/
13939  }
13940 
13941  consdata = SCIPconsGetData(cons);
13942  assert(consdata != NULL);
13943 
13944  return consdata->hmax;
13945 }
13946 
13947 /** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13949  SCIP* scip, /**< SCIP data structure */
13950  SCIP_CONS* cons /**< constraint data */
13951  )
13952 {
13953  SCIP_CONSDATA* consdata;
13954 
13955  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13956  {
13957  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13958  SCIPABORT();
13959  return NULL; /*lint !e527*/
13960  }
13961 
13962  consdata = SCIPconsGetData(cons);
13963  assert(consdata != NULL);
13964 
13965  return consdata->vars;
13966 }
13967 
13968 /** returns the activities of the cumulative constraint */ /*lint -e{715}*/
13970  SCIP* scip, /**< SCIP data structure */
13971  SCIP_CONS* cons /**< constraint data */
13972  )
13973 {
13974  SCIP_CONSDATA* consdata;
13975 
13976  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13977  {
13978  SCIPerrorMessage("constraint is not a cumulative constraint\n");
13979  SCIPABORT();
13980  return -1; /*lint !e527*/
13981  }
13982 
13983  consdata = SCIPconsGetData(cons);
13984  assert(consdata != NULL);
13985 
13986  return consdata->nvars;
13987 }
13988 
13989 /** returns the capacity of the cumulative constraint */ /*lint -e{715}*/
13991  SCIP* scip, /**< SCIP data structure */
13992  SCIP_CONS* cons /**< constraint data */
13993  )
13994 {
13995  SCIP_CONSDATA* consdata;
13996 
13997  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13998  {
13999  SCIPerrorMessage("constraint is not a cumulative constraint\n");
14000  SCIPABORT();
14001  return -1; /*lint !e527*/
14002  }
14003 
14004  consdata = SCIPconsGetData(cons);
14005  assert(consdata != NULL);
14006 
14007  return consdata->capacity;
14008 }
14009 
14010 /** returns the durations of the cumulative constraint */ /*lint -e{715}*/
14012  SCIP* scip, /**< SCIP data structure */
14013  SCIP_CONS* cons /**< constraint data */
14014  )
14015 {
14016  SCIP_CONSDATA* consdata;
14017 
14018  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14019  {
14020  SCIPerrorMessage("constraint is not a cumulative constraint\n");
14021  SCIPABORT();
14022  return NULL; /*lint !e527*/
14023  }
14024 
14025  consdata = SCIPconsGetData(cons);
14026  assert(consdata != NULL);
14027 
14028  return consdata->durations;
14029 }
14030 
14031 /** returns the demands of the cumulative constraint */ /*lint -e{715}*/
14033  SCIP* scip, /**< SCIP data structure */
14034  SCIP_CONS* cons /**< constraint data */
14035  )
14036 {
14037  SCIP_CONSDATA* consdata;
14038 
14039  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14040  {
14041  SCIPerrorMessage("constraint is not a cumulative constraint\n");
14042  SCIPABORT();
14043  return NULL; /*lint !e527*/
14044  }
14045 
14046  consdata = SCIPconsGetData(cons);
14047  assert(consdata != NULL);
14048 
14049  return consdata->demands;
14050 }
14051 
14052 /** check for the given starting time variables with their demands and durations if the cumulative conditions for the
14053  * given solution is satisfied
14054  */
14056  SCIP* scip, /**< SCIP data structure */
14057  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
14058  int nvars, /**< number of variables (jobs) */
14059  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14060  int* durations, /**< array containing corresponding durations */
14061  int* demands, /**< array containing corresponding demands */
14062  int capacity, /**< available cumulative capacity */
14063  int hmin, /**< left bound of time axis to be considered (including hmin) */
14064  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14065  SCIP_Bool* violated, /**< pointer to store if the cumulative condition is violated */
14066  SCIP_CONS* cons, /**< constraint which is checked */
14067  SCIP_Bool printreason /**< should the reason for the violation be printed? */
14068  )
14069 {
14070  assert(scip != NULL);
14071  assert(violated != NULL);
14072 
14073  SCIP_CALL( checkCumulativeCondition(scip, sol, nvars, vars, durations, demands, capacity, hmin, hmax,
14074  violated, cons, printreason) );
14075 
14076  return SCIP_OKAY;
14077 }
14078 
14079 /** normalize cumulative condition */ /*lint -e{715}*/
14081  SCIP* scip, /**< SCIP data structure */
14082  int nvars, /**< number of start time variables (activities) */
14083  SCIP_VAR** vars, /**< array of start time variables */
14084  int* durations, /**< array of durations */
14085  int* demands, /**< array of demands */
14086  int* capacity, /**< pointer to store the changed cumulative capacity */
14087  int* nchgcoefs, /**< pointer to count total number of changed coefficients */
14088  int* nchgsides /**< pointer to count number of side changes */
14089  )
14090 { /*lint --e{715}*/
14091  normalizeCumulativeCondition(scip, nvars, demands, capacity, nchgcoefs, nchgsides);
14092 
14093  return SCIP_OKAY;
14094 }
14095 
14096 /** searches for a time point within the cumulative condition were the cumulative condition can be split */
14098  SCIP* scip, /**< SCIP data structure */
14099  int nvars, /**< number of variables (jobs) */
14100  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14101  int* durations, /**< array containing corresponding durations */
14102  int* demands, /**< array containing corresponding demands */
14103  int capacity, /**< available cumulative capacity */
14104  int* hmin, /**< pointer to store the left bound of the effective horizon */
14105  int* hmax, /**< pointer to store the right bound of the effective horizon */
14106  int* split /**< point were the cumulative condition can be split */
14107  )
14108 {
14109  SCIP_CALL( computeEffectiveHorizonCumulativeCondition(scip, nvars, vars, durations, demands, capacity,
14110  hmin, hmax, split) );
14111 
14112  return SCIP_OKAY;
14113 }
14114 
14115 /** presolve cumulative condition w.r.t. effective horizon by detecting irrelevant variables */
14117  SCIP* scip, /**< SCIP data structure */
14118  int nvars, /**< number of start time variables (activities) */
14119  SCIP_VAR** vars, /**< array of start time variables */
14120  int* durations, /**< array of durations */
14121  int hmin, /**< left bound of time axis to be considered */
14122  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14123  SCIP_Bool* downlocks, /**< array storing if the variable has a down lock, or NULL */
14124  SCIP_Bool* uplocks, /**< array storing if the variable has an up lock, or NULL */
14125  SCIP_CONS* cons, /**< constraint which gets propagated, or NULL */
14126  SCIP_Bool* irrelevants, /**< array mark those variables which are irrelevant for the cumulative condition */
14127  int* nfixedvars, /**< pointer to store the number of fixed variables */
14128  int* nchgsides, /**< pointer to store the number of changed sides */
14129  SCIP_Bool* cutoff /**< buffer to store whether a cutoff is detected */
14130  )
14131 {
14132  if( nvars <= 1 )
14133  return SCIP_OKAY;
14134 
14135  /* presolve constraint form the earlier start time point of view */
14136  SCIP_CALL( presolveConsEst(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14137  irrelevants, nfixedvars, nchgsides, cutoff) );
14138 
14139  /* presolve constraint form the latest completion time point of view */
14140  SCIP_CALL( presolveConsLct(scip, nvars, vars, durations, hmin, hmax, downlocks, uplocks, cons,
14141  irrelevants, nfixedvars, nchgsides, cutoff) );
14142 
14143  return SCIP_OKAY;
14144 }
14145 
14146 /** propagate the given cumulative condition */
14148  SCIP* scip, /**< SCIP data structure */
14149  SCIP_PRESOLTIMING presoltiming, /**< current presolving timing */
14150  int nvars, /**< number of variables (jobs) */
14151  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14152  int* durations, /**< array containing corresponding durations */
14153  int* demands, /**< array containing corresponding demands */
14154  int capacity, /**< available cumulative capacity */
14155  int hmin, /**< left bound of time axis to be considered (including hmin) */
14156  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14157  SCIP_CONS* cons, /**< constraint which gets propagated */
14158  int* nchgbds, /**< pointer to store the number of variable bound changes */
14159  SCIP_Bool* initialized, /**< was conflict analysis initialized */
14160  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14161  SCIP_Bool* cutoff /**< pointer to store if the cumulative condition is violated */
14162  )
14163 {
14164  SCIP_CONSHDLR* conshdlr;
14165  SCIP_CONSHDLRDATA* conshdlrdata;
14166  SCIP_Bool redundant;
14167 
14168  assert(scip != NULL);
14169  assert(cons != NULL);
14170  assert(initialized != NULL);
14171  assert(*initialized == FALSE);
14172  assert(cutoff != NULL);
14173  assert(*cutoff == FALSE);
14174 
14175  /* find the cumulative constraint handler */
14176  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14177  if( conshdlr == NULL )
14178  {
14179  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14180  return SCIP_PLUGINNOTFOUND;
14181  }
14182 
14183  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14184  assert(conshdlrdata != NULL);
14185 
14186  redundant = FALSE;
14187 
14188  SCIP_CALL( propagateCumulativeCondition(scip, conshdlrdata, presoltiming,
14189  nvars, vars, durations, demands, capacity, hmin, hmax, cons,
14190  nchgbds, &redundant, initialized, explanation, cutoff) );
14191 
14192  return SCIP_OKAY;
14193 }
14194 
14195 /** resolve propagation w.r.t. the cumulative condition */
14197  SCIP* scip, /**< SCIP data structure */
14198  int nvars, /**< number of start time variables (activities) */
14199  SCIP_VAR** vars, /**< array of start time variables */
14200  int* durations, /**< array of durations */
14201  int* demands, /**< array of demands */
14202  int capacity, /**< cumulative capacity */
14203  int hmin, /**< left bound of time axis to be considered (including hmin) */
14204  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14205  SCIP_VAR* infervar, /**< the conflict variable whose bound change has to be resolved */
14206  int inferinfo, /**< the user information */
14207  SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
14208  SCIP_BDCHGIDX* bdchgidx, /**< the index of the bound change, representing the point of time where the change took place */
14209  SCIP_Real relaxedbd, /**< the relaxed bound which is sufficient to be explained */
14210  SCIP_Bool* explanation, /**< bool array which marks the variable which are part of the explanation if a cutoff was detected, or NULL */
14211  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
14212  )
14213 {
14214  SCIP_CALL( respropCumulativeCondition(scip, nvars, vars, durations, demands, capacity, hmin, hmax,
14215  infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, relaxedbd, TRUE, explanation, result) );
14216 
14217  return SCIP_OKAY;
14218 }
14219 
14220 /** this method visualizes the cumulative structure in GML format */
14222  SCIP* scip, /**< SCIP data structure */
14223  SCIP_CONS* cons /**< cumulative constraint */
14224  )
14225 {
14226  SCIP_CONSDATA* consdata;
14227  SCIP_HASHTABLE* vars;
14228  FILE* file;
14229  SCIP_VAR* var;
14230  char filename[SCIP_MAXSTRLEN];
14231  int nvars;
14232  int v;
14233 
14234  SCIP_RETCODE retcode = SCIP_OKAY;
14235 
14236  /* open file */
14237  (void)SCIPsnprintf(filename, SCIP_MAXSTRLEN, "%s.gml", SCIPconsGetName(cons));
14238  file = fopen(filename, "w");
14239 
14240  /* check if the file was open */
14241  if( file == NULL )
14242  {
14243  SCIPerrorMessage("cannot create file <%s> for writing\n", filename);
14244  SCIPprintSysError(filename);
14245  return SCIP_FILECREATEERROR;
14246  }
14247 
14248  consdata = SCIPconsGetData(cons);
14249  assert(consdata != NULL);
14250 
14251  nvars = consdata->nvars;
14252 
14253  SCIP_CALL_TERMINATE( retcode, SCIPhashtableCreate(&vars, SCIPblkmem(scip), nvars,
14254  SCIPvarGetHashkey, SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL), TERMINATE );
14255 
14256  /* create opening of the GML format */
14257  SCIPgmlWriteOpening(file, TRUE);
14258 
14259  for( v = 0; v < nvars; ++v )
14260  {
14261  char color[SCIP_MAXSTRLEN];
14262 
14263  var = consdata->vars[v];
14264  assert(var != NULL);
14265 
14266  SCIP_CALL_TERMINATE( retcode, SCIPhashtableInsert(vars, (void*)var) , TERMINATE );
14267 
14268  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 )
14269  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#0000ff");
14270  else if( !consdata->downlocks[v] || !consdata->uplocks[v] )
14271  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#00ff00");
14272  else
14273  (void)SCIPsnprintf(color, SCIP_MAXSTRLEN, "%s", "#ff0000");
14274 
14275  SCIPgmlWriteNode(file, (unsigned int)(size_t)var, SCIPvarGetName(var), "rectangle", color, NULL);
14276  }
14277 
14278  for( v = 0; v < nvars; ++v )
14279  {
14280  SCIP_VAR** vbdvars;
14281  int nvbdvars;
14282  int b;
14283 
14284  var = consdata->vars[v];
14285  assert(var != NULL);
14286 
14287  vbdvars = SCIPvarGetVlbVars(var);
14288  nvbdvars = SCIPvarGetNVlbs(var);
14289 
14290  for( b = 0; b < nvbdvars; ++b )
14291  {
14292  if( SCIPhashtableExists(vars, (void*)vbdvars[b]) )
14293  {
14294  SCIPgmlWriteArc(file, (unsigned int)(size_t)vbdvars[b], (unsigned int)(size_t)var, NULL, NULL);
14295  }
14296  }
14297 
14298 #if 0
14299  vbdvars = SCIPvarGetVubVars(var);
14300  nvbdvars = SCIPvarGetNVubs(var);
14301 
14302  for( b = 0; b < nvbdvars; ++b )
14303  {
14304  if( SCIPhashtableExists(vars, vbdvars[b]) )
14305  {
14306  SCIPgmlWriteArc(file, (unsigned int)(size_t)var, (unsigned int)(size_t)vbdvars[b], NULL, NULL);
14307  }
14308  }
14309 #endif
14310  }
14311 
14312  /* create closing of the GML format */
14313  SCIPgmlWriteClosing(file);
14314 TERMINATE:
14315  /* close file */
14316  fclose(file);
14317 
14318  SCIPhashtableFree(&vars);
14319 
14320  return retcode;
14321 }
14322 
14323 /** sets method to solve an individual cumulative condition */
14325  SCIP* scip, /**< SCIP data structure */
14326  SCIP_DECL_SOLVECUMULATIVE((*solveCumulative)) /**< method to use an individual cumulative condition */
14327  )
14328 {
14329  SCIP_CONSHDLR* conshdlr;
14330  SCIP_CONSHDLRDATA* conshdlrdata;
14331 
14332  /* find the cumulative constraint handler */
14333  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14334  if( conshdlr == NULL )
14335  {
14336  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14337  return SCIP_PLUGINNOTFOUND;
14338  }
14339 
14340  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14341  assert(conshdlrdata != NULL);
14342 
14343  conshdlrdata->solveCumulative = solveCumulative;
14344 
14345  return SCIP_OKAY;
14346 }
14347 
14348 /** solves given cumulative condition as independent sub problem
14349  *
14350  * @note If the problem was solved to the earliest start times (ests) and latest start times (lsts) array contain the
14351  * solution values; If the problem was not solved these two arrays contain the global bounds at the time the sub
14352  * solver was interrupted.
14353  */
14355  SCIP* scip, /**< SCIP data structure */
14356  int njobs, /**< number of jobs (activities) */
14357  SCIP_Real* ests, /**< array with the earlier start time for each job */
14358  SCIP_Real* lsts, /**< array with the latest start time for each job */
14359  SCIP_Real* objvals, /**< array of objective coefficients for each job (linear objective function), or NULL if none */
14360  int* durations, /**< array of durations */
14361  int* demands, /**< array of demands */
14362  int capacity, /**< cumulative capacity */
14363  int hmin, /**< left bound of time axis to be considered (including hmin) */
14364  int hmax, /**< right bound of time axis to be considered (not including hmax) */
14365  SCIP_Real timelimit, /**< time limit for solving in seconds */
14366  SCIP_Real memorylimit, /**< memory limit for solving in mega bytes (MB) */
14367  SCIP_Longint maxnodes, /**< maximum number of branch-and-bound nodes to solve the single cumulative constraint (-1: no limit) */
14368  SCIP_Bool* solved, /**< pointer to store if the problem is solved (to optimality) */
14369  SCIP_Bool* infeasible, /**< pointer to store if the problem is infeasible */
14370  SCIP_Bool* unbounded, /**< pointer to store if the problem is unbounded */
14371  SCIP_Bool* error /**< pointer to store if an error occurred */
14372  )
14373 {
14374  SCIP_CONSHDLR* conshdlr;
14375  SCIP_CONSHDLRDATA* conshdlrdata;
14376 
14377  (*solved) = TRUE;
14378  (*infeasible) = FALSE;
14379  (*unbounded) = FALSE;
14380  (*error) = FALSE;
14381 
14382  if( njobs == 0 )
14383  return SCIP_OKAY;
14384 
14385  /* find the cumulative constraint handler */
14386  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14387  if( conshdlr == NULL )
14388  {
14389  SCIPerrorMessage("" CONSHDLR_NAME " constraint handler not found\n");
14390  (*error) = TRUE;
14391  return SCIP_PLUGINNOTFOUND;
14392  }
14393 
14394  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14395  assert(conshdlrdata != NULL);
14396 
14397  /* abort if no time is left or not enough memory to create a copy of SCIP, including external memory usage */
14398  if( timelimit > 0.0 && memorylimit > 10 )
14399  {
14400  SCIP_CALL( conshdlrdata->solveCumulative(njobs, ests, lsts, objvals, durations, demands, capacity,
14401  hmin, hmax, timelimit, memorylimit, maxnodes, solved, infeasible, unbounded, error) );
14402  }
14403 
14404  return SCIP_OKAY;
14405 }
14406 
14407 /** creates the worst case resource profile, that is, all jobs are inserted with the earliest start and latest
14408  * completion time
14409  */
14411  SCIP* scip, /**< SCIP data structure */
14412  SCIP_PROFILE* profile, /**< resource profile */
14413  int nvars, /**< number of variables (jobs) */
14414  SCIP_VAR** vars, /**< array of integer variable which corresponds to starting times for a job */
14415  int* durations, /**< array containing corresponding durations */
14416  int* demands /**< array containing corresponding demands */
14417  )
14418 {
14419  SCIP_VAR* var;
14420  SCIP_HASHMAP* addedvars;
14421  int* copydemands;
14422  int* perm;
14423  int duration;
14424  int impliedest;
14425  int est;
14426  int impliedlct;
14427  int lct;
14428  int v;
14429 
14430  /* create hash map for variables which are added, mapping to their duration */
14431  SCIP_CALL( SCIPhashmapCreate(&addedvars, SCIPblkmem(scip), nvars) );
14432 
14433  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
14434  SCIP_CALL( SCIPallocBufferArray(scip, &copydemands, nvars) );
14435 
14436  /* sort variables w.r.t. job demands */
14437  for( v = 0; v < nvars; ++v )
14438  {
14439  copydemands[v] = demands[v];
14440  perm[v] = v;
14441  }
14442  SCIPsortDownIntInt(copydemands, perm, nvars);
14443 
14444  /* add each job with its earliest start and latest completion time into the resource profile */
14445  for( v = 0; v < nvars; ++v )
14446  {
14447  int idx;
14448 
14449  idx = perm[v];
14450  assert(idx >= 0 && idx < nvars);
14451 
14452  var = vars[idx];
14453  assert(var != NULL);
14454 
14455  duration = durations[idx];
14456  assert(duration > 0);
14457 
14458  est = SCIPconvertRealToInt(scip, SCIPvarGetLbLocal(var));
14459  SCIP_CALL( computeImpliedEst(scip, var, addedvars, &impliedest) );
14460 
14461  lct = SCIPconvertRealToInt(scip, SCIPvarGetUbLocal(var)) + duration;
14462  SCIP_CALL( computeImpliedLct(scip, var, duration, addedvars, &impliedlct) );
14463 
14464  if( impliedest < impliedlct )
14465  {
14466  SCIP_Bool infeasible;
14467  int pos;
14468 
14469  SCIP_CALL( SCIPprofileInsertCore(profile, impliedest, impliedlct, copydemands[v], &pos, &infeasible) );
14470  assert(!infeasible);
14471  assert(pos == -1);
14472  }
14473 
14474  if( est == impliedest && lct == impliedlct )
14475  {
14476  SCIP_CALL( SCIPhashmapInsertInt(addedvars, (void*)var, duration) );
14477  }
14478  }
14479 
14480  SCIPfreeBufferArray(scip, &copydemands);
14481  SCIPfreeBufferArray(scip, &perm);
14482 
14483  SCIPhashmapFree(&addedvars);
14484 
14485  return SCIP_OKAY;
14486 }
14487 
14488 /** computes w.r.t. the given worst case resource profile the first time point where the given capacity can be violated */ /*lint -e{715}*/
14489 int SCIPcomputeHmin(
14490  SCIP* scip, /**< SCIP data structure */
14491  SCIP_PROFILE* profile, /**< worst case resource profile */
14492  int capacity /**< capacity to check */
14493  )
14494 {
14495  int* timepoints;
14496  int* loads;
14497  int ntimepoints;
14498  int t;
14499 
14500  ntimepoints = SCIPprofileGetNTimepoints(profile);
14501  timepoints = SCIPprofileGetTimepoints(profile);
14502  loads = SCIPprofileGetLoads(profile);
14503 
14504  /* find first time point which potentially violates the capacity restriction */
14505  for( t = 0; t < ntimepoints - 1; ++t )
14506  {
14507  /* check if the time point exceed w.r.t. worst case profile the capacity */
14508  if( loads[t] > capacity )
14509  {
14510  assert(t == 0 || loads[t-1] <= capacity);
14511  return timepoints[t];
14512  }
14513  }
14514 
14515  return INT_MAX;
14516 }
14517 
14518 /** 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}*/
14519 int SCIPcomputeHmax(
14520  SCIP* scip, /**< SCIP data structure */
14521  SCIP_PROFILE* profile, /**< worst case profile */
14522  int capacity /**< capacity to check */
14523  )
14524 {
14525  int* timepoints;
14526  int* loads;
14527  int ntimepoints;
14528  int t;
14529 
14530  ntimepoints = SCIPprofileGetNTimepoints(profile);
14531  timepoints = SCIPprofileGetTimepoints(profile);
14532  loads = SCIPprofileGetLoads(profile);
14533 
14534  /* find last time point which potentially violates the capacity restriction */
14535  for( t = ntimepoints - 1; t >= 0; --t )
14536  {
14537  /* check if at time point t the worst case resource profile exceeds the capacity */
14538  if( loads[t] > capacity )
14539  {
14540  assert(t == ntimepoints-1 || loads[t+1] <= capacity);
14541  return timepoints[t+1];
14542  }
14543  }
14544 
14545  return INT_MIN;
14546 }
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:5205
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:2130
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:1994
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:1250
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:5322
#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:6663
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:590
#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:1482
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:4261
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:2488
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:1796
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:4439
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:8717
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:8278
#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:4353
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:5503
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:5617
static SCIP_RETCODE consdataCollectLinkingCons(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPrestartSolve(SCIP *scip)
Definition: scip_solve.c:3475
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:8403
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:718
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:8631
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